<!DOCTYPE html><html lang="zh-CN" data-theme="light"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0"><title>Spring高级45讲【第六章】：OTHER | 狼族少年、血狼</title><meta name="author" content="狼族少年、血狼"><meta name="copyright" content="狼族少年、血狼"><meta name="format-detection" content="telephone=no"><meta name="theme-color" content="#ffffff"><meta name="description" content="FactoryBeanFactoryBean是一个工厂Bean，是用来产生产品对象的，FactoryBean本身是由spring管理的，但其产生的产品类却是部分受到srping的管理，为什么这么说呢？下面做一个试验： 创建一个Bean2，由spring进行管理： 123@Componentpublic class Bean2 &amp;#123;&amp;#125;  创建一个Bean1，注意不直接交由sprin">
<meta property="og:type" content="article">
<meta property="og:title" content="Spring高级45讲【第六章】：OTHER">
<meta property="og:url" content="https://geekwolfman.github.io/2023/04/15/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E5%85%AD%E7%AB%A0%E3%80%91%EF%BC%9AOTHER.html">
<meta property="og:site_name" content="狼族少年、血狼">
<meta property="og:description" content="FactoryBeanFactoryBean是一个工厂Bean，是用来产生产品对象的，FactoryBean本身是由spring管理的，但其产生的产品类却是部分受到srping的管理，为什么这么说呢？下面做一个试验： 创建一个Bean2，由spring进行管理： 123@Componentpublic class Bean2 &amp;#123;&amp;#125;  创建一个Bean1，注意不直接交由sprin">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E5%85%AD%E7%AB%A0%E3%80%91%EF%BC%9AOTHER/00cover.jpg">
<meta property="article:published_time" content="2023-04-15T15:10:14.000Z">
<meta property="article:modified_time" content="2023-04-15T15:22:31.822Z">
<meta property="article:author" content="狼族少年、血狼">
<meta property="article:tag" content="spring">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E5%85%AD%E7%AB%A0%E3%80%91%EF%BC%9AOTHER/00cover.jpg"><link rel="shortcut icon" href="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/config/avatar/avatar.png"><link rel="canonical" href="https://geekwolfman.github.io/2023/04/15/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E5%85%AD%E7%AB%A0%E3%80%91%EF%BC%9AOTHER.html"><link rel="preconnect" href="//cdn.jsdelivr.net"/><link rel="preconnect" href="//busuanzi.ibruce.info"/><link rel="stylesheet" href="/css/index.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free/css/all.min.css" media="print" onload="this.media='all'"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/ui/dist/fancybox.min.css" media="print" onload="this.media='all'"><script>const GLOBAL_CONFIG = { 
  root: '/',
  algolia: undefined,
  localSearch: {"path":"/db.json","preload":false,"languages":{"hits_empty":"找不到您查询的内容：${query}"}},
  translate: undefined,
  noticeOutdate: undefined,
  highlight: {"plugin":"highlighjs","highlightCopy":true,"highlightLang":true,"highlightHeightLimit":false},
  copy: {
    success: '复制成功',
    error: '复制错误',
    noSupport: '浏览器不支持'
  },
  relativeDate: {
    homepage: false,
    post: false
  },
  runtime: '天',
  date_suffix: {
    just: '刚刚',
    min: '分钟前',
    hour: '小时前',
    day: '天前',
    month: '个月前'
  },
  copyright: undefined,
  lightbox: 'fancybox',
  Snackbar: undefined,
  source: {
    justifiedGallery: {
      js: 'https://cdn.jsdelivr.net/npm/flickr-justified-gallery/dist/fjGallery.min.js',
      css: 'https://cdn.jsdelivr.net/npm/flickr-justified-gallery/dist/fjGallery.min.css'
    }
  },
  isPhotoFigcaption: false,
  islazyload: false,
  isAnchor: false,
  percent: {
    toc: true,
    rightside: true,
  }
}</script><script id="config-diff">var GLOBAL_CONFIG_SITE = {
  title: 'Spring高级45讲【第六章】：OTHER',
  isPost: true,
  isHome: false,
  isHighlightShrink: false,
  isToc: true,
  postUpdate: '2023-04-15 23:22:31'
}</script><noscript><style type="text/css">
  #nav {
    opacity: 1
  }
  .justified-gallery img {
    opacity: 1
  }

  #recent-posts time,
  #post-meta time {
    display: inline !important
  }
</style></noscript><script>(win=>{
    win.saveToLocal = {
      set: function setWithExpiry(key, value, ttl) {
        if (ttl === 0) return
        const now = new Date()
        const expiryDay = ttl * 86400000
        const item = {
          value: value,
          expiry: now.getTime() + expiryDay,
        }
        localStorage.setItem(key, JSON.stringify(item))
      },

      get: function getWithExpiry(key) {
        const itemStr = localStorage.getItem(key)

        if (!itemStr) {
          return undefined
        }
        const item = JSON.parse(itemStr)
        const now = new Date()

        if (now.getTime() > item.expiry) {
          localStorage.removeItem(key)
          return undefined
        }
        return item.value
      }
    }
  
    win.getScript = url => new Promise((resolve, reject) => {
      const script = document.createElement('script')
      script.src = url
      script.async = true
      script.onerror = reject
      script.onload = script.onreadystatechange = function() {
        const loadState = this.readyState
        if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
        script.onload = script.onreadystatechange = null
        resolve()
      }
      document.head.appendChild(script)
    })
  
    win.getCSS = (url,id = false) => new Promise((resolve, reject) => {
      const link = document.createElement('link')
      link.rel = 'stylesheet'
      link.href = url
      if (id) link.id = id
      link.onerror = reject
      link.onload = link.onreadystatechange = function() {
        const loadState = this.readyState
        if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
        link.onload = link.onreadystatechange = null
        resolve()
      }
      document.head.appendChild(link)
    })
  
      win.activateDarkMode = function () {
        document.documentElement.setAttribute('data-theme', 'dark')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#0d0d0d')
        }
      }
      win.activateLightMode = function () {
        document.documentElement.setAttribute('data-theme', 'light')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#ffffff')
        }
      }
      const t = saveToLocal.get('theme')
    
          if (t === 'dark') activateDarkMode()
          else if (t === 'light') activateLightMode()
        
      const asideStatus = saveToLocal.get('aside-status')
      if (asideStatus !== undefined) {
        if (asideStatus === 'hide') {
          document.documentElement.classList.add('hide-aside')
        } else {
          document.documentElement.classList.remove('hide-aside')
        }
      }
    
    const detectApple = () => {
      if(/iPad|iPhone|iPod|Macintosh/.test(navigator.userAgent)){
        document.documentElement.classList.add('apple')
      }
    }
    detectApple()
    })(window)</script><meta name="generator" content="Hexo 6.3.0"></head><body><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/pace-js/themes/blue/pace-theme-minimal.min.css"/><script src="https://cdn.jsdelivr.net/npm/pace-js/pace.min.js"></script><div id="sidebar"><div id="menu-mask"></div><div id="sidebar-menus"><div class="avatar-img is-center"><img src="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/config/avatar/avatar.png" onerror="onerror=null;src='/img/friend_404.gif'" alt="avatar"/></div><div class="sidebar-site-data site-data is-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">57</div></a><a href="/tags/"><div class="headline">标签</div><div class="length-num">14</div></a><a href="/categories/"><div class="headline">分类</div><div class="length-num">9</div></a></div><hr/><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 归档</span></a></div><div class="menus_item"><a class="site-page" href="/gallery/"><i class="fa-fw fas fa-images"></i><span> 画廊</span></a></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fas fa-link"></i><span> 友链</span></a></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fas fa-paper-plane"></i><span> 关于</span></a></div></div></div></div><div class="post" id="body-wrap"><header class="post-bg" id="page-header" style="background-image: url('https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E5%85%AD%E7%AB%A0%E3%80%91%EF%BC%9AOTHER/00cover.jpg')"><nav id="nav"><span id="blog-info"><a href="/" title="狼族少年、血狼"><span class="site-name">狼族少年、血狼</span></a></span><div id="menus"><div id="search-button"><a class="site-page social-icon search" href="javascript:void(0);"><i class="fas fa-search fa-fw"></i><span> 搜索</span></a></div><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 归档</span></a></div><div class="menus_item"><a class="site-page" href="/gallery/"><i class="fa-fw fas fa-images"></i><span> 画廊</span></a></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fas fa-link"></i><span> 友链</span></a></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fas fa-paper-plane"></i><span> 关于</span></a></div></div><div id="toggle-menu"><a class="site-page" href="javascript:void(0);"><i class="fas fa-bars fa-fw"></i></a></div></div></nav><div id="post-info"><h1 class="post-title">Spring高级45讲【第六章】：OTHER</h1><div id="post-meta"><div class="meta-firstline"><span class="post-meta-date"><i class="far fa-calendar-alt fa-fw post-meta-icon"></i><span class="post-meta-label">发表于</span><time class="post-meta-date-created" datetime="2023-04-15T15:10:14.000Z" title="发表于 2023-04-15 23:10:14">2023-04-15</time><span class="post-meta-separator">|</span><i class="fas fa-history fa-fw post-meta-icon"></i><span class="post-meta-label">更新于</span><time class="post-meta-date-updated" datetime="2023-04-15T15:22:31.822Z" title="更新于 2023-04-15 23:22:31">2023-04-15</time></span><span class="post-meta-categories"><span class="post-meta-separator">|</span><i class="fas fa-inbox fa-fw post-meta-icon"></i><a class="post-meta-categories" href="/categories/%E5%8E%9F%E7%90%86%E6%8E%A2%E7%A9%B6/">原理探究</a></span></div><div class="meta-secondline"><span class="post-meta-separator">|</span><span class="post-meta-wordcount"><i class="far fa-file-word fa-fw post-meta-icon"></i><span class="post-meta-label">字数总计:</span><span class="word-count">10k</span><span class="post-meta-separator">|</span><i class="far fa-clock fa-fw post-meta-icon"></i><span class="post-meta-label">阅读时长:</span><span>45分钟</span></span><span class="post-meta-separator">|</span><span class="post-meta-pv-cv" id="" data-flag-title="Spring高级45讲【第六章】：OTHER"><i class="far fa-eye fa-fw post-meta-icon"></i><span class="post-meta-label">阅读量:</span><span id="busuanzi_value_page_pv"><i class="fa-solid fa-spinner fa-spin"></i></span></span></div></div></div></header><main class="layout" id="content-inner"><div id="post"><article class="post-content" id="article-container"><h1 id="FactoryBean"><a href="#FactoryBean" class="headerlink" title="FactoryBean"></a><strong>FactoryBean</strong></h1><p><code>FactoryBean</code>是一个工厂<code>Bean</code>，是用来产生产品对象的，<code>FactoryBean</code>本身是由<code>spring</code>管理的，但其产生的产品类却是部分受到<code>srping</code>的管理，为什么这么说呢？下面做一个试验：</p>
<p>创建一个<code>Bean2</code>，由<code>spring</code>进行管理：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Bean2</span> &#123;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>创建一个<code>Bean1</code>，注意不直接交由<code>spring</code>管理，没有加<code>@Component</code>注解，但实现了<code>BeanFactoryAware</code>接口，我们看看在<code>Bean1</code>创建的各个时期会不会回调实现的方法。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Bean1</span> <span class="keyword">implements</span> <span class="title class_">BeanFactoryAware</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Logger</span> <span class="variable">log</span> <span class="operator">=</span> LoggerFactory.getLogger(Bean1.class);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> Bean2 bean2;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setBean2</span><span class="params">(Bean2 bean2)</span> &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;setBean2(&#123;&#125;)&quot;</span>, bean2);</span><br><span class="line">        <span class="built_in">this</span>.bean2 = bean2;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> Bean2 <span class="title function_">getBean2</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> bean2;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@PostConstruct</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">init</span><span class="params">()</span> &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;init&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setBeanFactory</span><span class="params">(BeanFactory beanFactory)</span> <span class="keyword">throws</span> BeansException &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;setBeanFactory(&#123;&#125;)&quot;</span>, beanFactory);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>接下来创建一个<code>Bean1FactoryBean</code>，其实现了<code>FactoryBean</code>接口，泛型为<code>Bean1</code>，即生成类型为<code>Bean1</code>的<code>bean</code>，其中主要实现了三个方法：</p>
<ol>
<li><code>getObjectType()</code>：获取生成的<code>Bean</code>的类型</li>
<li><code>isSingleton()</code>：是否是单例，<code>true</code>为单例，<code>false</code>为多例</li>
<li><code>getObject()</code>：具体生成<code>Bean</code>的逻辑</li>
</ol>
<p>注意<code>Bean1FactoryBean</code>添加了<code>@Component(&quot;bean1&quot;)</code>注解，交由<code>spring</code>进行管理，取名为<code>&quot;bean1&quot;</code></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Component(&quot;bean1&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Bean1FactoryBean</span> <span class="keyword">implements</span> <span class="title class_">FactoryBean</span>&lt;Bean1&gt; &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Logger</span> <span class="variable">log</span> <span class="operator">=</span> LoggerFactory.getLogger(Bean1FactoryBean.class);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 决定了根据【类型】获取或依赖注入能否成功</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> Class&lt;?&gt; getObjectType() &#123;</span><br><span class="line">        <span class="keyword">return</span> Bean1.class;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 决定了 getObject() 方法被调用一次还是多次</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">isSingleton</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> Bean1 <span class="title function_">getObject</span><span class="params">()</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        <span class="type">Bean1</span> <span class="variable">bean1</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Bean1</span>();</span><br><span class="line">        log.debug(<span class="string">&quot;create bean: &#123;&#125;&quot;</span>, bean1);</span><br><span class="line">        <span class="keyword">return</span> bean1;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>编写启动类:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@ComponentScan</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">A43</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="type">AnnotationConfigApplicationContext</span> <span class="variable">context</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AnnotationConfigApplicationContext</span>(A43.class);</span><br><span class="line">        <span class="type">Bean1</span> <span class="variable">bean1</span> <span class="operator">=</span> (Bean1) context.getBean(<span class="string">&quot;bean1&quot;</span>);</span><br><span class="line">        System.out.println(bean1);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>运行启动类，查看控制台：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">[DEBUG] 21:22:32.003 [main] com.itheima.a43.Bean1FactoryBean    - create bean: com.itheima.a43.Bean1@60bd273d </span><br><span class="line">com.itheima.a43.Bean1@60bd273d</span><br></pre></td></tr></table></figure>

<p>我们根据名称获取<code>Bean</code>，比较奇怪的一点是我们获取的名称是<code>&quot;bean1&quot;</code>，在一般情况下获取的应该是<code>@Component(&quot;bean1&quot;)</code>注解标注的类型，而<code>Bean1FactoryBean</code>获取的却是其生成的产品的类型，即<code>Bean1</code>。</p>
<p>观察输出，我们发现<code>Bean1</code>并不是由<code>spring</code>创建的，在创建过程中并没有调用<strong>依赖注入、初始化方法、</strong>**<code>setBeanFactory()</code>**等方法。但<code>spring</code>并不是完全没有参与产品类的创建，我们给<code>Bean1</code>添加一个后处理器，分别在<code>Bean1</code>初始化前和初始化打印相应日志：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Bean1PostProcessor</span> <span class="keyword">implements</span> <span class="title class_">BeanPostProcessor</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Logger</span> <span class="variable">log</span> <span class="operator">=</span> LoggerFactory.getLogger(Bean1PostProcessor.class);</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> Object <span class="title function_">postProcessBeforeInitialization</span><span class="params">(Object bean, String beanName)</span> <span class="keyword">throws</span> BeansException &#123;</span><br><span class="line">        <span class="keyword">if</span> (beanName.equals(<span class="string">&quot;bean1&quot;</span>) &amp;&amp; bean <span class="keyword">instanceof</span> Bean1) &#123;</span><br><span class="line">            log.debug(<span class="string">&quot;before [&#123;&#125;] init&quot;</span>, beanName);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> bean;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> Object <span class="title function_">postProcessAfterInitialization</span><span class="params">(Object bean, String beanName)</span> <span class="keyword">throws</span> BeansException &#123;</span><br><span class="line">        <span class="keyword">if</span> (beanName.equals(<span class="string">&quot;bean1&quot;</span>) &amp;&amp; bean <span class="keyword">instanceof</span> Bean1) &#123;</span><br><span class="line">            log.debug(<span class="string">&quot;after [&#123;&#125;] init&quot;</span>, beanName);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> bean;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><code>BeanPostProcessor</code>可以在<code>Bean</code>初始化前做一些增强，也可以在<code>Bean</code>初始化后做一些增强。</p>
<p>运行启动类，查看控制台：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">[DEBUG] 21:29:51.019 [main] com.itheima.a43.Bean1FactoryBean    - create bean: com.itheima.a43.Bean1@38cee291 </span><br><span class="line">[DEBUG] 21:29:51.038 [main] com.itheima.a43.Bean1PostProcessor  - after [bean1] init </span><br><span class="line">com.itheima.a43.Bean1@38cee291</span><br></pre></td></tr></table></figure>

<p>我们发现初始化前的增强逻辑没有调用，却调用了初始化后增强的逻辑，而<strong>创建代理</strong>就是在<code>Bean</code>初始化后进行的，因此产品对象是可以通过代理增强的。</p>
<p>所以说产品对象部分受<code>spring</code>管理。</p>
<p>注意产品对象单例并没有存放在<code>BeanFcatory</code>的单例池中，而是存在<code>BeanFactory</code>的<code>factoryBeanObjectCache</code>成员中。</p>
<p>另外，如果我们在<code>getObjectType()</code>方法中返回<code>null</code>，那么通过类型获取<code>Bean</code>的时候会报错：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">Exception in thread &quot;main&quot; org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type &#x27;com.itheima.a43.Bean1&#x27; available</span><br><span class="line">        at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:351)</span><br><span class="line">        at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:342)</span><br><span class="line">        at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1172)</span><br><span class="line">        at com.itheima.a43.A43.main(A43.java:19)</span><br></pre></td></tr></table></figure>

<p>如果要获取<code>FactoryBean</code>本身，有两种方式：</p>
<ol>
<li>通过类型获取</li>
<li>通过$+bean名称获取</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">System.out.println(context.getBean(Bean1FactoryBean.class));</span><br><span class="line">System.out.println(context.getBean(<span class="string">&quot;&amp;bean1&quot;</span>));</span><br></pre></td></tr></table></figure>

<p><strong>FactoryBean总结：</strong></p>
<ol>
<li>它的作用是用制造创建过程较为复杂的产品，如<code>SqlSessionFactory</code>, 但<code>@Bean</code>已具备等价功能</li>
<li>被<code>FactoryBean</code>创建的产品<ol>
<li>会认为创建、依赖注入、<code>Aware</code>接口回调、前初始化这些操作都是<code>FactoryBean</code>的职责, 这些流程都不会走</li>
<li>唯有后初始化的流程会走, 也就是产品可以被代理增强</li>
<li>单例的产品不会存储于<code>BeanFactory</code>的<code>singletonObjects</code>成员中, 而是另一个 <code>factoryBeanObjectCache</code>成员中</li>
</ol>
</li>
<li>按名字去获取时, 拿到的是产品对象, 名字前面加<code>&amp;</code>获取的是工厂对象</li>
</ol>
<h1 id="Indexed原理"><a href="#Indexed原理" class="headerlink" title="@Indexed原理"></a><strong>@Indexed原理</strong></h1><p><code>spring</code>组件扫描的效率是非常低的，会扫描包下的所有类，一个一个解析注解，如果有<code>@Component</code>、<code>@Bean</code>等注解的话，就会生成<code>BeanDefinition</code>并加入容器中。<code>spring</code>的扫描范围非常大，会影响到<code>spring</code>的启动速度。因此，<code>spring</code>在5.0中做了一个优化，能解决此问题。</p>
<p>编写测试代码：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Bean1</span> &#123;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Bean2</span> &#123;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Bean3</span> &#123;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">A44</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> IOException, NoSuchMethodException, InvocationTargetException, IllegalAccessException &#123;</span><br><span class="line">        <span class="type">DefaultListableBeanFactory</span> <span class="variable">beanFactory</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DefaultListableBeanFactory</span>();</span><br><span class="line">        <span class="comment">// 组件扫描的核心类</span></span><br><span class="line">        <span class="type">ClassPathBeanDefinitionScanner</span> <span class="variable">scanner</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ClassPathBeanDefinitionScanner</span>(beanFactory);</span><br><span class="line">        scanner.scan(A44.class.getPackageName());</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span> (String name : beanFactory.getBeanDefinitionNames()) &#123;</span><br><span class="line">            System.out.println(name);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>运行启动类，查看控制台：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">bean1</span><br><span class="line">bean2</span><br><span class="line">bean3</span><br><span class="line">org.springframework.context.annotation.internalConfigurationAnnotationProcessor</span><br><span class="line">org.springframework.context.annotation.internalAutowiredAnnotationProcessor</span><br><span class="line">org.springframework.context.annotation.internalCommonAnnotationProcessor</span><br><span class="line">org.springframework.context.event.internalEventListenerProcessor</span><br><span class="line">org.springframework.context.event.internalEventListenerFactory</span><br></pre></td></tr></table></figure>

<p><code>bean1</code>、<code>bean2</code>、<code>bean3</code>都被加入到了容器中。</p>
<p>接下来我们添加依赖：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-context-indexer<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">optional</span>&gt;</span>true<span class="tag">&lt;/<span class="name">optional</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>并在<code>target/classes</code>目录下创建<code>META-INF/spring.components</code>文件，其内容为：</p>
<figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">com.itheima.a44.Bean1</span>=<span class="string">org.springframework.stereotype.Component</span></span><br></pre></td></tr></table></figure>

<p>再次运行启动类，查看控制台：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">bean1</span><br><span class="line">org.springframework.context.annotation.internalConfigurationAnnotationProcessor</span><br><span class="line">org.springframework.context.annotation.internalAutowiredAnnotationProcessor</span><br><span class="line">org.springframework.context.annotation.internalCommonAnnotationProcessor</span><br><span class="line">org.springframework.context.event.internalEventListenerProcessor</span><br><span class="line">org.springframework.context.event.internalEventListenerFactory</span><br></pre></td></tr></table></figure>

<p>发现只有<code>bean1</code>被加入了容器中。</p>
<p>为什么呢？</p>
<p>在<code>spring</code>5.0以后<code>ClassPathBeanDefinitionScanner</code>的<code>scan()</code>方法并不是首先进行包扫描，它首先是找一个位于<code>target/classesMETA-INF</code>目录下的<code>spring.components</code>文件。如果这个文件提供了<code>Bean</code>的名称，则优先加载此文件中的<code>Bean</code>，后续就不会再走<code>jar</code>包扫描的过程了。</p>
<p><code>spring.components</code>的配置格式为：</p>
<ol>
<li><code>key</code>为类的路径</li>
<li><code>value</code>为类上添加的注解</li>
</ol>
<p>还记得我们添加的<code>spring-context-indexer</code>坐标吗？这个依赖的作用就是在编译阶段去找添加了<code>@Index</code>注解的类，如果有就生成位置文件加入到<code>spring.components</code>中。我们点开<code>@Component</code>注解：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Target(&#123;ElementType.TYPE&#125;)</span></span><br><span class="line"><span class="meta">@Retention(RetentionPolicy.RUNTIME)</span></span><br><span class="line"><span class="meta">@Documented</span></span><br><span class="line"><span class="meta">@Indexed</span></span><br><span class="line"><span class="keyword">public</span> <span class="meta">@interface</span> Component &#123;</span><br><span class="line">    String <span class="title function_">value</span><span class="params">()</span> <span class="keyword">default</span> <span class="string">&quot;&quot;</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>发现<code>@Component</code>注解组合了<code>@Indexed</code>注解。但此时我们手动创建了这个文件，因此<code>spring</code>会直接使用我们创建的文件，而不是生成<code>spring.components</code>文件。</p>
<p><code>@Indexed</code>的作用就是在<strong>编译阶段</strong>，解析<code>@Indexed</code>注解，在<code>target/classesMETA-INF</code>目录下生成<code>spring.components</code>文件，在运行时直接读取此文件加载<code>BeanDefinition</code>而不是重新扫描包。</p>
<p>**<code>@Indexed</code>**<strong>总结：</strong></p>
<ol>
<li><code>@Indexed</code>的原理，在<strong>编译时</strong>就根据<code>@Indexed</code>生成<code>META-INF/spring.components</code>文件， 扫描时如果发现<code>META-INF/spring.components</code>存在, 则以它为准加载<code>BeanDefinition</code></li>
<li>否则, 会遍历包下所有<code>class</code>资源 (包括<code>jar</code>内的)</li>
</ol>
<h1 id="代理进一步理解"><a href="#代理进一步理解" class="headerlink" title="代理进一步理解"></a><strong>代理进一步理解</strong></h1><p><code>spring</code>代理有几个特点：</p>
<ol>
<li><strong>依赖注入和初始化</strong>影响的是原始对象</li>
<li>代理与目标是两个对象，二者成员变量并不共用数据</li>
<li><code>static</code>方法、<code>final</code>方法、<code>private</code>方法均无法增强</li>
</ol>
<p>代码演示第1个特点：</p>
<p>创建<code>Bean1</code>类，其中有初始化方法、依赖注入方法。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Bean1</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Logger</span> <span class="variable">log</span> <span class="operator">=</span> LoggerFactory.getLogger(Bean1.class);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">protected</span> Bean2 bean2;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">protected</span> <span class="type">boolean</span> initialized;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setBean2</span><span class="params">(Bean2 bean2)</span> &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;setBean2(Bean2 bean2)&quot;</span>);</span><br><span class="line">        <span class="built_in">this</span>.bean2 = bean2;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@PostConstruct</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">init</span><span class="params">()</span> &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;init&quot;</span>);</span><br><span class="line">        initialized = <span class="literal">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> Bean2 <span class="title function_">getBean2</span><span class="params">()</span> &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;getBean2()&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> bean2;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">isInitialized</span><span class="params">()</span> &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;isInitialized()&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> initialized;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>创建切面<code>MyAspect</code> ，对<code>Bean1</code>中的所有方法进行增强。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Aspect</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MyAspect</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Before(&quot;execution(* com.itheima.a45.Bean1.*(..))&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">before</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;before&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>创建启动类：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">A45</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        <span class="type">ConfigurableApplicationContext</span> <span class="variable">context</span> <span class="operator">=</span> SpringApplication.run(A45.class, args);</span><br><span class="line"></span><br><span class="line">        <span class="type">Bean1</span> <span class="variable">proxy</span> <span class="operator">=</span> context.getBean(Bean1.class);</span><br><span class="line">        System.out.println(proxy.getBean2());</span><br><span class="line">        System.out.println(proxy.isInitialized());</span><br><span class="line">        context.close();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>运行启动类，查看控制台：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">[DEBUG] 17:07:35.297 [main] com.itheima.a45.Bean1               - setBean2(Bean2 bean2) </span><br><span class="line">[DEBUG] 17:07:35.297 [main] com.itheima.a45.Bean1               - init </span><br><span class="line">before</span><br><span class="line">[DEBUG] 17:07:35.913 [main] com.itheima.a45.Bean1               - getBean2() </span><br><span class="line">com.itheima.a45.Bean2@1a1c21b4</span><br><span class="line">before</span><br><span class="line">[DEBUG] 17:07:35.913 [main] com.itheima.a45.Bean1               - isInitialized() </span><br><span class="line">true</span><br></pre></td></tr></table></figure>

<p>我们发现，在初始化和依赖注入的时候代理是不生效的，说明在这两个阶段使用的是<code>Bean</code>的原始对象；我们拿<code>Bean</code>的实例时，实际上拿到的时<code>Bean</code>的代理对象，此时代理才生效。</p>
<p>代码演示第2个特点：</p>
<p>编写方法打印代理对象与目标对象的属性值：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">showProxyAndTarget</span><span class="params">(Bean1 proxy)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">    System.out.println(<span class="string">&quot;&gt;&gt;&gt;&gt;&gt; 代理中的成员变量&quot;</span>);</span><br><span class="line">    System.out.println(<span class="string">&quot;\tinitialized=&quot;</span> + proxy.initialized);</span><br><span class="line">    System.out.println(<span class="string">&quot;\tbean2=&quot;</span> + proxy.bean2);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (proxy <span class="keyword">instanceof</span> Advised advised) &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;&gt;&gt;&gt;&gt;&gt; 目标中的成员变量&quot;</span>);</span><br><span class="line">        <span class="type">Bean1</span> <span class="variable">target</span> <span class="operator">=</span> (Bean1) advised.getTargetSource().getTarget();</span><br><span class="line">        System.out.println(<span class="string">&quot;\tinitialized=&quot;</span> + target.initialized);</span><br><span class="line">        System.out.println(<span class="string">&quot;\tbean2=&quot;</span> + target.bean2);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>调用此方法，查看控制台：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt;&gt;&gt; 代理中的成员变量</span><br><span class="line">        initialized=false</span><br><span class="line">        bean2=null</span><br><span class="line">&gt;&gt;&gt;&gt;&gt; 目标中的成员变量</span><br><span class="line">        initialized=true</span><br><span class="line">        bean2=com.itheima.a45.Bean2@640d604</span><br></pre></td></tr></table></figure>

<p>我们发现代理对象中的成员变量是没有值的，因为代理对象没有参与依赖注入、初始化的过程，而目标对象中的成员变量是有值的。一般我们使用的是代理对象，而访问代理对象的属性时一般通过<code>get</code>、<code>set</code>方法，最终会访问目标对象中的值。</p>
<p>代码演示第3个特点：</p>
<p>在<code>Bean1</code>类中增加以下几个方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">m1</span><span class="params">()</span> &#123;</span><br><span class="line">    System.out.println(<span class="string">&quot;m1() 成员方法&quot;</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">final</span> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">m2</span><span class="params">()</span> &#123;</span><br><span class="line">    System.out.println(<span class="string">&quot;m2() final 方法&quot;</span>);</span><br><span class="line">    </span><br><span class="line">    </span><br><span class="line">    </span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">m3</span><span class="params">()</span> &#123;</span><br><span class="line">    System.out.println(<span class="string">&quot;m3() static 方法&quot;</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">m4</span><span class="params">()</span> &#123;</span><br><span class="line">    System.out.println(<span class="string">&quot;m4() private 方法&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>然后通过代理对象调用：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">Bean1</span> <span class="variable">proxy</span> <span class="operator">=</span> context.getBean(Bean1.class);</span><br><span class="line">proxy.m1();</span><br><span class="line">proxy.m2();</span><br><span class="line">proxy.m3();</span><br><span class="line"><span class="type">Method</span> <span class="variable">m4</span> <span class="operator">=</span> Bean1.class.getDeclaredMethod(<span class="string">&quot;m4&quot;</span>);</span><br><span class="line">m4.setAccessible(<span class="literal">true</span>);</span><br><span class="line">m4.invoke(proxy);</span><br></pre></td></tr></table></figure>

<p>查看控制台：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">before</span><br><span class="line">m1() 成员方法</span><br><span class="line">m2() final 方法</span><br><span class="line">m3() static 方法</span><br><span class="line">m4() private 方法</span><br></pre></td></tr></table></figure>

<p>只有成员方法被增强了。</p>
<p><code>static</code>方法、<code>final</code>方法、<code>private</code>方法这些方法都不能使用方法重写机制进行增强，如果需要增强可以使用<code>aspectj</code>或者<code>agent</code>等在编译时增强的方式。</p>
<h1 id="Value装配底层"><a href="#Value装配底层" class="headerlink" title="@Value装配底层"></a><strong>@Value装配底层</strong></h1><p>编写代码手动解析<code>@Value</code>注解：</p>
<p>首先编写<code>Bean1</code>，其中使用<code>@Value</code>注解注入了两个值，<code>home</code>属性从环境变量中取值，<code>age</code>属性的值是固定的。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Bean1</span> &#123;</span><br><span class="line">    <span class="meta">@Value(&quot;$&#123;JAVA_HOME&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> String home;</span><br><span class="line">    <span class="meta">@Value(&quot;18&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> <span class="type">int</span> age;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>编写<code>main()</code>方法，创建容器并创建解析器。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">    <span class="type">AnnotationConfigApplicationContext</span> <span class="variable">context</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AnnotationConfigApplicationContext</span>(A46.class);</span><br><span class="line">    <span class="type">DefaultListableBeanFactory</span> <span class="variable">beanFactory</span> <span class="operator">=</span> context.getDefaultListableBeanFactory();</span><br><span class="line">    <span class="type">ContextAnnotationAutowireCandidateResolver</span> <span class="variable">resolver</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ContextAnnotationAutowireCandidateResolver</span>();</span><br><span class="line">    resolver.setBeanFactory(beanFactory);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>编写测试，其中<code>DependencyDescriptor</code>构造方法有两个参数：</p>
<ol>
<li>传入需要解析的字段</li>
<li>是否必须有这个字段，如果为<code>true</code>，则必须要有此字段；为<code>false</code>，没有此字段则会报错</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">test1</span><span class="params">(AnnotationConfigApplicationContext context, ContextAnnotationAutowireCandidateResolver resolver, Field field)</span> &#123;</span><br><span class="line">    <span class="type">DependencyDescriptor</span> <span class="variable">dd1</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DependencyDescriptor</span>(field, <span class="literal">false</span>);</span><br><span class="line">    <span class="comment">// 获取 @Value 的内容</span></span><br><span class="line">    <span class="type">String</span> <span class="variable">value</span> <span class="operator">=</span> resolver.getSuggestedValue(dd1).toString();</span><br><span class="line">    System.out.println(value);</span><br><span class="line">    <span class="comment">// 解析 $&#123;&#125;</span></span><br><span class="line">    value = context.getEnvironment().resolvePlaceholders(value);</span><br><span class="line">    System.out.println(value);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在<code>main()</code>方法中调用<code>test1()</code>：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">test1(context, resolver, Bean1.class.getDeclaredField(<span class="string">&quot;home&quot;</span>));</span><br><span class="line">test1(context, resolver, Bean1.class.getDeclaredField(<span class="string">&quot;age&quot;</span>));</span><br></pre></td></tr></table></figure>

<p>查看输出：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">$&#123;JAVA_HOME&#125;</span><br><span class="line">C:\Path\jdk-14.0.1</span><br><span class="line">18</span><br><span class="line">18</span><br></pre></td></tr></table></figure>

<p>能正确解析<code>@Value</code>注解中的值。</p>
<p>实际上在以上代码中并没有做类型转换的功能，我们可以打印一下类型：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">System.out.println(value.getClass());</span><br></pre></td></tr></table></figure>

<p>查看输出：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">$&#123;JAVA_HOME&#125;</span><br><span class="line">C:\Path\jdk-14.0.1</span><br><span class="line">class java.lang.String</span><br><span class="line">18</span><br><span class="line">18</span><br><span class="line">class java.lang.String</span><br></pre></td></tr></table></figure>

<p>发现<code>age</code>也是<code>String</code>类型，说明此时只解析了数据但没有进行类型转换，我们手动做一下类型转换，使用的是<code>spring</code>提供的高级类型转换器：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">test2</span><span class="params">(AnnotationConfigApplicationContext context, ContextAnnotationAutowireCandidateResolver resolver, Field field)</span> &#123;</span><br><span class="line">    <span class="type">DependencyDescriptor</span> <span class="variable">dd1</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DependencyDescriptor</span>(field, <span class="literal">false</span>);</span><br><span class="line">    <span class="comment">// 获取 @Value 的内容</span></span><br><span class="line">    <span class="type">String</span> <span class="variable">value</span> <span class="operator">=</span> resolver.getSuggestedValue(dd1).toString();</span><br><span class="line">    System.out.println(value);</span><br><span class="line">    <span class="comment">// 解析 $&#123;&#125;</span></span><br><span class="line">    value = context.getEnvironment().resolvePlaceholders(value);</span><br><span class="line">    System.out.println(value);</span><br><span class="line">    System.out.println(value.getClass());</span><br><span class="line">    <span class="type">Object</span> <span class="variable">age</span> <span class="operator">=</span> context.getBeanFactory().getTypeConverter().convertIfNecessary(value, dd1.getDependencyType());</span><br><span class="line">    System.out.println(age.getClass());</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>再次运行，查看输出：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">$&#123;JAVA_HOME&#125;</span><br><span class="line">C:\Path\jdk-14.0.1</span><br><span class="line">class java.lang.String</span><br><span class="line">class java.lang.String</span><br><span class="line">18</span><br><span class="line">18</span><br><span class="line">class java.lang.String</span><br><span class="line">class java.lang.Integer</span><br></pre></td></tr></table></figure>

<p>成功进行了类型转换。</p>
<p><code>@Value</code>注解除了能进行值注入，也支持依赖注入，可以使用<code>spel</code>表达式，以下代码就是通过<code>spel</code>表达式在<code>Bean2</code>中注入名称为<code>bean3</code>的<code>Bean</code>。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Bean2</span> &#123;</span><br><span class="line">    <span class="meta">@Value(&quot;#&#123;@bean3&#125;&quot;)</span> </span><br><span class="line">    <span class="keyword">private</span> Bean3 bean3;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Component(&quot;bean3&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Bean3</span> &#123;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>要解析类似<code>#&#123;&#125;</code>的<code>spel</code>表达式，我们需要使用到<code>BeanExpressionResolver</code>：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">test3</span><span class="params">(AnnotationConfigApplicationContext context, ContextAnnotationAutowireCandidateResolver resolver, Field field)</span> &#123;</span><br><span class="line">    <span class="type">DependencyDescriptor</span> <span class="variable">dd1</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DependencyDescriptor</span>(field, <span class="literal">false</span>);</span><br><span class="line">    <span class="comment">// 获取 @Value 的内容</span></span><br><span class="line">    <span class="type">String</span> <span class="variable">value</span> <span class="operator">=</span> resolver.getSuggestedValue(dd1).toString();</span><br><span class="line">    System.out.println(value);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 解析 $&#123;&#125;</span></span><br><span class="line">    value = context.getEnvironment().resolvePlaceholders(value);</span><br><span class="line">    System.out.println(value);</span><br><span class="line">    System.out.println(value.getClass());</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 解析 #&#123;&#125;</span></span><br><span class="line">    <span class="type">Object</span> <span class="variable">bean3</span> <span class="operator">=</span> context.getBeanFactory().getBeanExpressionResolver().evaluate(value, <span class="keyword">new</span> <span class="title class_">BeanExpressionContext</span>(context.getBeanFactory(), <span class="literal">null</span>));</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 类型转换</span></span><br><span class="line">    <span class="type">Object</span> <span class="variable">result</span> <span class="operator">=</span> context.getBeanFactory().getTypeConverter().convertIfNecessary(bean3, dd1.getDependencyType());</span><br><span class="line">    System.out.println(result);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>调用<code>test3()</code>方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">test3(context, resolver, Bean2.class.getDeclaredField(<span class="string">&quot;bean3&quot;</span>));</span><br></pre></td></tr></table></figure>

<p>查看输出：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">#&#123;@bean3&#125;</span><br><span class="line">#&#123;@bean3&#125;</span><br><span class="line">class java.lang.String</span><br><span class="line">com.itheima.a46.A46$Bean3@1c9b0314</span><br></pre></td></tr></table></figure>

<p><code>@Value</code>注解底层执行的顺序就和上面的顺序类似：</p>
<ol>
<li>首先获取<code>@Value</code>原始内容</li>
<li>解析<code>$&#123;&#125;</code>表达式</li>
<li>解析<code>#&#123;&#125;</code>表达式</li>
<li>进行必要的类型转换</li>
</ol>
<p><code>@Value</code>中还可以进行嵌套解析，例如<code>Bean4</code>中内层嵌套了<code>$&#123;&#125;</code>表达式，外侧嵌套了<code>#&#123;&#125;</code>表达式，同时<code>#&#123;&#125;</code>也支持拼接操作，解析的步骤就是先解析内层，再解析外层。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Bean4</span> &#123;</span><br><span class="line">    <span class="meta">@Value(&quot;#&#123;&#x27;hello, &#x27; + &#x27;$&#123;JAVA_HOME&#125;&#x27;&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> String value;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>调用<code>test3()</code>方法测试：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">#&#123;&#x27;hello, &#x27; + &#x27;$&#123;JAVA_HOME&#125;&#x27;&#125;</span><br><span class="line">#&#123;&#x27;hello, &#x27; + &#x27;C:\Path\jdk-14.0.1&#x27;&#125;</span><br><span class="line">class java.lang.String</span><br><span class="line">hello, C:\Path\jdk-14.0.1</span><br></pre></td></tr></table></figure>

<p>能正确解析内容。</p>
<h1 id="Autowired装配底层"><a href="#Autowired装配底层" class="headerlink" title="@Autowired装配底层"></a><strong>@Autowired装配底层</strong></h1><p><code>@Autowired</code>注解使用场景较多，主要有以下几种方式：</p>
<ol>
<li>根据成员变量的类型注入</li>
<li>根据参数的类型注入</li>
<li>结果包装为<code>Optional</code></li>
<li>结果包装为<code>ObjectProvider</code>、<code>ObjectFactory</code></li>
<li>对<code>@Lazy</code>注解的处理</li>
</ol>
<p>接下来演示这几种方式的使用。</p>
<ol>
<li>根据成员变量的类型注入</li>
</ol>
<p>创建<code>Bean2</code>：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Component(&quot;bean2&quot;)</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Bean2</span> &#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">toString</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">super</span>.toString();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>创建<code>Bean1</code>，自动注入属性<code>Bean2</code>:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Bean1</span> &#123;</span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> Bean2 bean2;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>解析成员变量的类型注入需要使用到<code>DefaultListableBeanFactory</code>的<code>doResolveDependency()</code>方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> NoSuchFieldException, NoSuchMethodException &#123;</span><br><span class="line">    <span class="type">AnnotationConfigApplicationContext</span> <span class="variable">context</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AnnotationConfigApplicationContext</span>(A47_1.class);</span><br><span class="line">    <span class="type">DefaultListableBeanFactory</span> <span class="variable">beanFactory</span> <span class="operator">=</span> context.getDefaultListableBeanFactory();</span><br><span class="line">    <span class="comment">// 1. 根据成员变量的类型注入</span></span><br><span class="line">    <span class="type">DependencyDescriptor</span> <span class="variable">dd1</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DependencyDescriptor</span>(Bean1.class.getDeclaredField(<span class="string">&quot;bean2&quot;</span>), <span class="literal">false</span>);</span><br><span class="line">    System.out.println(beanFactory.doResolveDependency(dd1, <span class="string">&quot;bean1&quot;</span>, <span class="literal">null</span>, <span class="literal">null</span>));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>运行<code>main()</code>方法，查看输出：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">com.itheima.a47.A47_1$Bean2@723ca036</span><br></pre></td></tr></table></figure>

<ol start="2">
<li>根据参数的类型注入</li>
</ol>
<p>在<code>Bean1</code>中添加方法注入：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Bean1</span> &#123;</span><br><span class="line">    <span class="meta">@Autowired</span> </span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setBean2</span><span class="params">(Bean2 bean2)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.bean2 = bean2;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>根据参数的类型注入和成员变量的类型注入类似，只不过创建<code>DependencyDescriptor</code>时，使用的是重载的构造方法，传入方法参数：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> NoSuchFieldException, NoSuchMethodException &#123;</span><br><span class="line">    <span class="type">AnnotationConfigApplicationContext</span> <span class="variable">context</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AnnotationConfigApplicationContext</span>(A47_1.class);</span><br><span class="line">    <span class="type">DefaultListableBeanFactory</span> <span class="variable">beanFactory</span> <span class="operator">=</span> context.getDefaultListableBeanFactory();</span><br><span class="line">    System.out.println(<span class="string">&quot;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&quot;</span>);</span><br><span class="line">    <span class="comment">// 2. 根据参数的类型注入</span></span><br><span class="line">    <span class="type">Method</span> <span class="variable">setBean2</span> <span class="operator">=</span> Bean1.class.getDeclaredMethod(<span class="string">&quot;setBean2&quot;</span>, Bean2.class);</span><br><span class="line">    <span class="type">DependencyDescriptor</span> <span class="variable">dd2</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DependencyDescriptor</span>(<span class="keyword">new</span> <span class="title class_">MethodParameter</span>(setBean2, <span class="number">0</span>), <span class="literal">false</span>);</span><br><span class="line">    System.out.println(beanFactory.doResolveDependency(dd2, <span class="string">&quot;bean2&quot;</span>, <span class="literal">null</span>, <span class="literal">null</span>));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>运行<code>main()</code>方法，查看输出：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">com.itheima.a47.A47_1$Bean2@723ca036</span><br></pre></td></tr></table></figure>

<ol start="3">
<li>结果包装为<code>Optional</code></li>
</ol>
<p>有时候注入<code>Bean</code>时会将其包装为<code>Optional</code>，例如：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Bean1</span> &#123;</span><br><span class="line">    <span class="meta">@Autowired</span> </span><br><span class="line">    <span class="keyword">private</span> Optional&lt;Bean2&gt; bean3;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>以上代码想要注入的是内嵌的<code>Bean2</code>类型，而不是<code>Optional</code>类型。</p>
<p><code>spring</code>也支持解析内嵌类型，使用的是<code>DependencyDescriptor</code>的<code>increaseNestingLevel()</code>方法获取内嵌的类型。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">A47_1</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> NoSuchFieldException, NoSuchMethodException &#123;</span><br><span class="line">        <span class="type">AnnotationConfigApplicationContext</span> <span class="variable">context</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AnnotationConfigApplicationContext</span>(A47_1.class);</span><br><span class="line">        <span class="type">DefaultListableBeanFactory</span> <span class="variable">beanFactory</span> <span class="operator">=</span> context.getDefaultListableBeanFactory();</span><br><span class="line">        <span class="comment">// 3. 结果包装为 Optional&lt;Bean2&gt;</span></span><br><span class="line">        <span class="type">DependencyDescriptor</span> <span class="variable">dd3</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DependencyDescriptor</span>(Bean1.class.getDeclaredField(<span class="string">&quot;bean3&quot;</span>), <span class="literal">false</span>);</span><br><span class="line">        <span class="keyword">if</span> (dd3.getDependencyType() == Optional.class) &#123;</span><br><span class="line">            dd3.increaseNestingLevel();</span><br><span class="line">            <span class="type">Object</span> <span class="variable">result</span> <span class="operator">=</span> beanFactory.doResolveDependency(dd3, <span class="string">&quot;bean3&quot;</span>, <span class="literal">null</span>, <span class="literal">null</span>);</span><br><span class="line">            System.out.println(Optional.ofNullable(result));</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>

<p>运行<code>main()</code>方法，查看输出：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Optional[com.itheima.a47.A47_1$Bean2@723ca036]</span><br></pre></td></tr></table></figure>

<ol start="4">
<li>结果包装为<code>ObjectProvider</code>、<code>ObjectFactory</code></li>
</ol>
<p>有时候注入<code>Bean</code>时会将其包装为<code>ObjectFactory</code>，例如：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Bean1</span> &#123;</span><br><span class="line">    <span class="meta">@Autowired</span> </span><br><span class="line">    <span class="keyword">private</span> ObjectFactory&lt;Bean2&gt; bean4;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>以上代码想要注入的是内嵌的<code>Bean2</code>类型，而不是<code>ObjectFactory</code>类型。</p>
<p><code>spring</code>也支持解析内嵌类型，使用的是<code>DependencyDescriptor</code>的<code>increaseNestingLevel()</code>方法获取内嵌的类型。</p>
<p>同时只有在调用<code>ObjectFactory</code>的<code>getObject()</code>方法时，才想要拿到真正的<code>Bean</code>，因此我们可以延迟加载<code>Bean</code>，只有在调用<code>ObjectFactory</code>的<code>getObject()</code>方法时我们才真正执行初始化<code>Bean</code>的逻辑：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> NoSuchFieldException, NoSuchMethodException &#123;</span><br><span class="line">    <span class="type">AnnotationConfigApplicationContext</span> <span class="variable">context</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AnnotationConfigApplicationContext</span>(A47_1.class);</span><br><span class="line">    <span class="type">DefaultListableBeanFactory</span> <span class="variable">beanFactory</span> <span class="operator">=</span> context.getDefaultListableBeanFactory();d1, <span class="string">&quot;bean1&quot;</span>, <span class="literal">null</span>, <span class="literal">null</span>));</span><br><span class="line">    <span class="comment">// 4. 结果包装为 ObjectProvider,ObjectFactory</span></span><br><span class="line">    <span class="type">DependencyDescriptor</span> <span class="variable">dd4</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DependencyDescriptor</span>(Bean1.class.getDeclaredField(<span class="string">&quot;bean4&quot;</span>), <span class="literal">false</span>);</span><br><span class="line">    <span class="keyword">if</span> (dd4.getDependencyType() == ObjectFactory.class) &#123;</span><br><span class="line">        dd4.increaseNestingLevel();</span><br><span class="line">        <span class="type">ObjectFactory</span> <span class="variable">objectFactory</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectFactory</span>() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="keyword">public</span> Object <span class="title function_">getObject</span><span class="params">()</span> <span class="keyword">throws</span> BeansException &#123;</span><br><span class="line">                <span class="keyword">return</span> beanFactory.doResolveDependency(dd4, <span class="string">&quot;bean4&quot;</span>, <span class="literal">null</span>, <span class="literal">null</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;;</span><br><span class="line">        System.out.println(objectFactory.getObject());</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>运行<code>main()</code>方法，查看输出：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">com.itheima.a47.A47_1$Bean2@723ca036</span><br></pre></td></tr></table></figure>

<ol start="5">
<li>对<code>@Lazy</code>注解的处理</li>
</ol>
<p><code>@Lazy</code>注解的作用有：</p>
<ul>
<li>当<code>@Lazy</code>放在类上，表示在启动的时候不会创建<code>bean</code>对象，当使用的时候才会创建</li>
<li>当<code>@Lazy</code>放在<code>@Bean</code>注解的方法上，表示在启动的时候不会创建<code>bean</code>对象，当使用的时候才会创建</li>
<li>当<code>@Lazy</code>放在<code>@Autowired</code>注解的属性上， 并不会直接给属性赋上真正的值，只是会赋值一个代理对象，当真正使用到这个属性的时候，才会去容器中找到一个符合的对象。在使用的时候，也会先执行代理对象的逻辑，然后再是真正bean对象的逻辑。</li>
<li>写在方法或者方法参数前面上，效果和写在属性上是一样的，开始注入的只是代理对象，当真正调用的时候才会调用对应对象的逻辑</li>
<li>写在构造方法或者构造方法参数前面上，和以上逻辑一样</li>
</ul>
<p>修改<code>Bean1</code>类：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Bean1</span> &#123;</span><br><span class="line">    <span class="meta">@Lazy</span> </span><br><span class="line">    <span class="meta">@Autowired</span> </span><br><span class="line">    <span class="keyword">private</span> Bean2 bean2;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>这里我们是将<code>@Lazy</code>放在<code>@Autowired</code>注解的属性上，因此会给属性赋值一个代理对象，这里使用的解析器是<code>ContextAnnotationAutowireCandidateResolver</code>：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> NoSuchFieldException, NoSuchMethodException &#123;</span><br><span class="line">    <span class="type">AnnotationConfigApplicationContext</span> <span class="variable">context</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AnnotationConfigApplicationContext</span>(A47_1.class);</span><br><span class="line">    <span class="type">DefaultListableBeanFactory</span> <span class="variable">beanFactory</span> <span class="operator">=</span> context.getDefaultListableBeanFactory();</span><br><span class="line">    <span class="comment">// 5. 对 @Lazy 的处理</span></span><br><span class="line">    <span class="type">DependencyDescriptor</span> <span class="variable">dd5</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DependencyDescriptor</span>(Bean1.class.getDeclaredField(<span class="string">&quot;bean2&quot;</span>), <span class="literal">false</span>);</span><br><span class="line">    <span class="type">ContextAnnotationAutowireCandidateResolver</span> <span class="variable">resolver</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ContextAnnotationAutowireCandidateResolver</span>();</span><br><span class="line">    resolver.setBeanFactory(beanFactory);</span><br><span class="line">    <span class="type">Object</span> <span class="variable">proxy</span> <span class="operator">=</span> resolver.getLazyResolutionProxyIfNecessary(dd5, <span class="string">&quot;bean2&quot;</span>);</span><br><span class="line">    System.out.println(proxy);</span><br><span class="line">    System.out.println(proxy.getClass());</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>运行<code>main()</code>方法，查看输出：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">com.itheima.a47.A47_1$Bean2@723ca036</span><br><span class="line">class com.itheima.a47.A47_1$Bean2$$EnhancerBySpringCGLIB$$537a559d</span><br></pre></td></tr></table></figure>

<p>以上的很多种情况我们都用到了<code>DefaultListableBeanFactory</code>的<code>doResolveDependency()</code>方法，其实<code>@Value</code>注解、<code>@Autowired</code>注解最终都会进入<code>doResolveDependency()</code>方法的逻辑。</p>
<p>只不过<code>doResolveDependency()</code>会优先处理<code>@Value</code>注解的字符串类型</p>
<p><code>doResolveDependency()</code>处理可以处理多种类型的注入，例如：</p>
<ol>
<li>数组类型</li>
<li><code>List</code>类型</li>
<li>特殊类型，例如<code>applicationContext</code></li>
<li>泛型</li>
<li>配合<code>@Qualifier</code>注解</li>
</ol>
<p>接下来我们模拟<code>doResolveDependency()</code>对以上类型的注入步骤。</p>
<p>准备基础类：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">interface</span> <span class="title class_">Dao</span>&lt;T&gt; &#123;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">interface</span> <span class="title class_">Service</span> &#123;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Target</span> &#123;</span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> Service[] serviceArray;</span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> List&lt;Service&gt; serviceList;</span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> ConfigurableApplicationContext applicationContext;</span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> Dao&lt;Teacher&gt; dao;</span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="meta">@Qualifier(&quot;service2&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> Service service;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Component(&quot;dao1&quot;)</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Dao1</span> <span class="keyword">implements</span> <span class="title class_">Dao</span>&lt;Student&gt; &#123;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Component(&quot;dao2&quot;)</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Dao2</span> <span class="keyword">implements</span> <span class="title class_">Dao</span>&lt;Teacher&gt; &#123;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Student</span> &#123;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Teacher</span> &#123;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Component(&quot;service1&quot;)</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Service1</span> <span class="keyword">implements</span> <span class="title class_">Service</span> &#123;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Component(&quot;service2&quot;)</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Service2</span> <span class="keyword">implements</span> <span class="title class_">Service</span> &#123;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Component(&quot;service3&quot;)</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Service3</span> <span class="keyword">implements</span> <span class="title class_">Service</span> &#123;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<ol>
<li>模拟数组类型的解析</li>
</ol>
<p>对于数组类型的解析主要思路是拿到数组中元素的类型，根据类型从容器中获取<code>Bean</code>，最后将这些<code>Bean</code>转换为数组进行返回：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">testArray</span><span class="params">(DefaultListableBeanFactory beanFactory)</span> <span class="keyword">throws</span> NoSuchFieldException &#123;</span><br><span class="line">    <span class="type">DependencyDescriptor</span> <span class="variable">dd1</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DependencyDescriptor</span>(Target.class.getDeclaredField(<span class="string">&quot;serviceArray&quot;</span>), <span class="literal">true</span>);</span><br><span class="line">    <span class="keyword">if</span> (dd1.getDependencyType().isArray()) &#123;</span><br><span class="line">        <span class="comment">// 获取数组中元素的真实类型</span></span><br><span class="line">        Class&lt;?&gt; componentType = dd1.getDependencyType().getComponentType();</span><br><span class="line">        System.out.println(componentType);</span><br><span class="line">        String[] names = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, componentType);</span><br><span class="line">        List&lt;Object&gt; beans = <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;();</span><br><span class="line">        <span class="keyword">for</span> (String name : names) &#123;</span><br><span class="line">            System.out.println(name);</span><br><span class="line">            <span class="comment">// 获取Bean</span></span><br><span class="line">            <span class="type">Object</span> <span class="variable">bean</span> <span class="operator">=</span> dd1.resolveCandidate(name, componentType, beanFactory);</span><br><span class="line">            beans.add(bean);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 将list转换为数组</span></span><br><span class="line">        <span class="type">Object</span> <span class="variable">array</span> <span class="operator">=</span> beanFactory.getTypeConverter().convertIfNecessary(beans, dd1.getDependencyType());</span><br><span class="line">        System.out.println(array);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>编写<code>main()</code>调用：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> NoSuchFieldException, IllegalAccessException &#123;</span><br><span class="line">    <span class="type">AnnotationConfigApplicationContext</span> <span class="variable">context</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AnnotationConfigApplicationContext</span>(A47_2.class);</span><br><span class="line">    <span class="type">DefaultListableBeanFactory</span> <span class="variable">beanFactory</span> <span class="operator">=</span> context.getDefaultListableBeanFactory();</span><br><span class="line">    System.out.println(<span class="string">&quot;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt; 1. 数组类型&quot;</span>);</span><br><span class="line">    testArray(beanFactory);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>查看输出：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt; 1. 数组类型</span><br><span class="line">interface com.itheima.a47.A47_2$Service</span><br><span class="line">service3</span><br><span class="line">service2</span><br><span class="line">service1</span><br><span class="line">[Lcom.itheima.a47.A47_2$Service;@3de8f619</span><br></pre></td></tr></table></figure>

<ol start="2">
<li>模拟<code>list</code>类型的解析</li>
</ol>
<p>对于<code>list</code>类型的解析主要思路是拿到<code>list</code>中元素的类型，根据类型从容器中获取<code>Bean</code>，最后将这些<code>Bean</code>转换为<code>list</code>进行返回：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">testList</span><span class="params">(DefaultListableBeanFactory beanFactory)</span> <span class="keyword">throws</span> NoSuchFieldException &#123;</span><br><span class="line">    <span class="type">DependencyDescriptor</span> <span class="variable">dd2</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DependencyDescriptor</span>(Target.class.getDeclaredField(<span class="string">&quot;serviceList&quot;</span>), <span class="literal">true</span>);</span><br><span class="line">    <span class="keyword">if</span> (dd2.getDependencyType() == List.class) &#123;</span><br><span class="line">        <span class="comment">// 获取list中元素的真实类型</span></span><br><span class="line">        Class&lt;?&gt; resolve = dd2.getResolvableType().getGeneric().resolve();</span><br><span class="line">        System.out.println(resolve);</span><br><span class="line">        List&lt;Object&gt; list = <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;();</span><br><span class="line">        String[] names = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, resolve);</span><br><span class="line">        <span class="keyword">for</span> (String name : names) &#123;</span><br><span class="line">            <span class="type">Object</span> <span class="variable">bean</span> <span class="operator">=</span> dd2.resolveCandidate(name, resolve, beanFactory);</span><br><span class="line">            <span class="comment">// 获取Bean</span></span><br><span class="line">            list.add(bean);</span><br><span class="line">        &#125;</span><br><span class="line">        System.out.println(list);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>编写<code>main()</code>调用：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> NoSuchFieldException, IllegalAccessException &#123;</span><br><span class="line">    <span class="type">AnnotationConfigApplicationContext</span> <span class="variable">context</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AnnotationConfigApplicationContext</span>(A47_2.class);</span><br><span class="line">    <span class="type">DefaultListableBeanFactory</span> <span class="variable">beanFactory</span> <span class="operator">=</span> context.getDefaultListableBeanFactory();</span><br><span class="line">    System.out.println(<span class="string">&quot;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt; 2. List 类型&quot;</span>);</span><br><span class="line">    testList(beanFactory);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>查看输出：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt; 2. List 类型</span><br><span class="line">interface com.itheima.a47.A47_2$Service</span><br><span class="line">[com.itheima.a47.A47_2$Service3@5fb759d6, com.itheima.a47.A47_2$Service2@4b8d604b, com.itheima.a47.A47_2$Service1@5e7cd6cc]</span><br></pre></td></tr></table></figure>

<ol start="3">
<li>模拟特殊类型的解析</li>
</ol>
<p>我们要注入一个特殊的类型<code>ConfigurableApplicationContext</code>，打开其类图：</p>
<p><img src="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E5%85%AD%E7%AB%A0%E3%80%91%EF%BC%9AOTHER/01.png" alt="img"></p>
<p><code>ConfigurableApplicationContext</code>其实是<code>ApplicationContext</code>的子类型，这种特殊类型并不是容器中的<code>Bean</code>。</p>
<p>最终所有的<code>Bean</code>会在<code>DefaultListableBeanFactory</code>中，打开<code>DefaultListableBeanFactory</code>类图：</p>
<p><img src="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E5%85%AD%E7%AB%A0%E3%80%91%EF%BC%9AOTHER/02.png" alt="img"></p>
<p><code>DefaultListableBeanFactory</code>实现了<code>DefaultSingletonBeanRegistry</code>，进入<code>DefaultSingletonBeanRegistry</code>类中，它有一个<code>singletonObjects</code>属性：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">final</span> Map&lt;String, Object&gt; singletonObjects = <span class="keyword">new</span> <span class="title class_">ConcurrentHashMap</span>(<span class="number">256</span>);</span><br></pre></td></tr></table></figure>

<p>最终所有的<code>Bean</code>都会放在<code>singletonObjects</code>中，<code>key</code>为<code>Bean</code>的名称，<code>value</code>为<code>Bean</code>的实例对象。但这里面没有<code>ApplicationContext</code>、<code>BeanFactory</code>等特殊类型。</p>
<p>这些特殊类型其实是放在<code>DefaultListableBeanFactory</code>中的<code>resolvableDependencies</code>属性中：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">final</span> Map&lt;Class&lt;?&gt;, Object&gt; resolvableDependencies;</span><br></pre></td></tr></table></figure>

<p><code>resolvableDependencies</code>的<code>key</code>为对象的类型，<code>value</code>为实例对象。这些特殊类型加入<code>resolvableDependencies</code>的时机是<code>ApplicationContext</code>调用<code>refresh()</code>方法。</p>
<p>进入<code>AbstractApplicationContext</code>类的<code>refresh()</code>方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">refresh</span><span class="params">()</span> <span class="keyword">throws</span> BeansException, IllegalStateException &#123;</span><br><span class="line">    <span class="keyword">synchronized</span>(<span class="built_in">this</span>.startupShutdownMonitor) &#123;</span><br><span class="line">        <span class="comment">// ...</span></span><br><span class="line">        <span class="built_in">this</span>.prepareBeanFactory(beanFactory);</span><br><span class="line">        <span class="comment">// ...</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>进入<code>prepareBeanFactory()</code>方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">prepareBeanFactory</span><span class="params">(ConfigurableListableBeanFactory beanFactory)</span> &#123;</span><br><span class="line">    <span class="comment">// ...</span></span><br><span class="line">    <span class="comment">// 加入特殊类型</span></span><br><span class="line">    beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);</span><br><span class="line">    beanFactory.registerResolvableDependency(ResourceLoader.class, <span class="built_in">this</span>);</span><br><span class="line">    beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, <span class="built_in">this</span>);</span><br><span class="line">    beanFactory.registerResolvableDependency(ApplicationContext.class, <span class="built_in">this</span>);</span><br><span class="line">    beanFactory.addBeanPostProcessor(<span class="keyword">new</span> <span class="title class_">ApplicationListenerDetector</span>(<span class="built_in">this</span>));</span><br><span class="line">    <span class="comment">// ...</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>因此我们需要到<code>resolvableDependencies</code>中去取这些特殊类型。</p>
<p>编写测试代码：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">testApplicationContext</span><span class="params">(DefaultListableBeanFactory beanFactory)</span> <span class="keyword">throws</span> NoSuchFieldException, IllegalAccessException &#123;</span><br><span class="line">    <span class="type">DependencyDescriptor</span> <span class="variable">dd3</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DependencyDescriptor</span>(Target.class.getDeclaredField(<span class="string">&quot;applicationContext&quot;</span>), <span class="literal">true</span>);</span><br><span class="line">    <span class="type">Field</span> <span class="variable">resolvableDependencies</span> <span class="operator">=</span> DefaultListableBeanFactory.class.getDeclaredField(<span class="string">&quot;resolvableDependencies&quot;</span>);</span><br><span class="line">    resolvableDependencies.setAccessible(<span class="literal">true</span>);</span><br><span class="line">    Map&lt;Class&lt;?&gt;, Object&gt; dependencies = (Map&lt;Class&lt;?&gt;, Object&gt;) resolvableDependencies.get(beanFactory);</span><br><span class="line">    <span class="keyword">for</span> (Map.Entry&lt;Class&lt;?&gt;, Object&gt; entry : dependencies.entrySet()) &#123;</span><br><span class="line">        <span class="comment">// 左边类型                      右边类型</span></span><br><span class="line">        <span class="keyword">if</span> (entry.getKey().isAssignableFrom(dd3.getDependencyType())) &#123;</span><br><span class="line">            System.out.println(entry.getValue());</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>编写<code>main()</code>调用：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> NoSuchFieldException, IllegalAccessException &#123;</span><br><span class="line">    <span class="type">AnnotationConfigApplicationContext</span> <span class="variable">context</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AnnotationConfigApplicationContext</span>(A47_2.class);</span><br><span class="line">    <span class="type">DefaultListableBeanFactory</span> <span class="variable">beanFactory</span> <span class="operator">=</span> context.getDefaultListableBeanFactory();</span><br><span class="line">    System.out.println(<span class="string">&quot;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt; 3. applicationContext&quot;</span>);</span><br><span class="line">    testApplicationContext(beanFactory);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>查看输出：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt; 3. applicationContext</span><br><span class="line">org.springframework.context.annotation.AnnotationConfigApplicationContext@2a40cd94, started on Fri Apr 14 21:28:31 CST 2023</span><br></pre></td></tr></table></figure>

<ol start="4">
<li>模拟泛型的解析</li>
</ol>
<p>对于泛型的解析，我们不仅要比较外层类型，还要比较内层泛型的类型，编写测试代码：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">testGeneric</span><span class="params">(DefaultListableBeanFactory beanFactory)</span> <span class="keyword">throws</span> NoSuchFieldException &#123;</span><br><span class="line">    <span class="type">DependencyDescriptor</span> <span class="variable">dd4</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DependencyDescriptor</span>(Target.class.getDeclaredField(<span class="string">&quot;dao&quot;</span>), <span class="literal">true</span>);</span><br><span class="line">    Class&lt;?&gt; type = dd4.getDependencyType();</span><br><span class="line">    <span class="type">ContextAnnotationAutowireCandidateResolver</span> <span class="variable">resolver</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ContextAnnotationAutowireCandidateResolver</span>();</span><br><span class="line">    resolver.setBeanFactory(beanFactory);</span><br><span class="line">    <span class="keyword">for</span> (String name : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, type)) &#123;</span><br><span class="line">        <span class="type">BeanDefinition</span> <span class="variable">bd</span> <span class="operator">=</span> beanFactory.getMergedBeanDefinition(name);</span><br><span class="line">        <span class="comment">// 对比 BeanDefinition 与 DependencyDescriptor 的泛型是否匹配</span></span><br><span class="line">        <span class="keyword">if</span> (resolver.isAutowireCandidate(<span class="keyword">new</span> <span class="title class_">BeanDefinitionHolder</span>(bd, name), dd4)) &#123;</span><br><span class="line">            System.out.println(name);</span><br><span class="line">            System.out.println(dd4.resolveCandidate(name, type, beanFactory));</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>首先拿到属性的类型，根据属性类型获取所有<code>Bean</code>的名称，再根据<code>Bean</code>的名称获取<code>BeanDefinition</code>，<code>BeanDefinition</code>中就有<code>Bean</code>的泛型信息，最后使用<code>ContextAnnotationAutowireCandidateResolver</code>的<code>isAutowireCandidate()</code>方法匹配泛型。</p>
<p>编写<code>main()</code>调用：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> NoSuchFieldException, IllegalAccessException &#123;</span><br><span class="line">    <span class="type">AnnotationConfigApplicationContext</span> <span class="variable">context</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AnnotationConfigApplicationContext</span>(A47_2.class);</span><br><span class="line">    <span class="type">DefaultListableBeanFactory</span> <span class="variable">beanFactory</span> <span class="operator">=</span> context.getDefaultListableBeanFactory();</span><br><span class="line">    System.out.println(<span class="string">&quot;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt; 4. 泛型&quot;</span>);</span><br><span class="line">    testGeneric(beanFactory);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>查看输出：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt; 4. 泛型</span><br><span class="line">dao2</span><br><span class="line">com.itheima.a47.A47_2$Dao2@29d80d2b</span><br></pre></td></tr></table></figure>

<ol start="5">
<li>模拟<code>@Qualifier</code>的解析</li>
</ol>
<p><code>ContextAnnotationAutowireCandidateResolver</code>的<code>isAutowireCandidate()</code>方法可以匹配<code>@Qualifier</code>注解，我们使用此方法即可。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">testQualifier</span><span class="params">(DefaultListableBeanFactory beanFactory)</span> <span class="keyword">throws</span> NoSuchFieldException &#123;</span><br><span class="line">    <span class="type">DependencyDescriptor</span> <span class="variable">dd5</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DependencyDescriptor</span>(Target.class.getDeclaredField(<span class="string">&quot;service&quot;</span>), <span class="literal">true</span>);</span><br><span class="line">    Class&lt;?&gt; type = dd5.getDependencyType();</span><br><span class="line">    <span class="type">ContextAnnotationAutowireCandidateResolver</span> <span class="variable">resolver</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ContextAnnotationAutowireCandidateResolver</span>();</span><br><span class="line">    resolver.setBeanFactory(beanFactory);</span><br><span class="line">    <span class="keyword">for</span> (String name : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, type)) &#123;</span><br><span class="line">        <span class="type">BeanDefinition</span> <span class="variable">bd</span> <span class="operator">=</span> beanFactory.getMergedBeanDefinition(name);</span><br><span class="line">        <span class="keyword">if</span> (resolver.isAutowireCandidate(<span class="keyword">new</span> <span class="title class_">BeanDefinitionHolder</span>(bd, name), dd5)) &#123;</span><br><span class="line">            System.out.println(name);</span><br><span class="line">            System.out.println(dd5.resolveCandidate(name, type, beanFactory));</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>编写<code>main()</code>调用：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> NoSuchFieldException, IllegalAccessException &#123;</span><br><span class="line">    <span class="type">AnnotationConfigApplicationContext</span> <span class="variable">context</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AnnotationConfigApplicationContext</span>(A47_2.class);</span><br><span class="line">    <span class="type">DefaultListableBeanFactory</span> <span class="variable">beanFactory</span> <span class="operator">=</span> context.getDefaultListableBeanFactory();</span><br><span class="line">    System.out.println(<span class="string">&quot;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt; 5. @Qualifier&quot;</span>);</span><br><span class="line">    testQualifier(beanFactory);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>查看输出：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt; 5. @Qualifier</span><br><span class="line">service2</span><br><span class="line">com.itheima.a47.A47_2$Service2@4b8d604b</span><br></pre></td></tr></table></figure>

<p>考虑以下场景，有一个接口<code>Service</code>:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">interface</span> <span class="title class_">Service</span> &#123;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>容器中有3个实现了此接口的<code>Bean</code>：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Component(&quot;service1&quot;)</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Service1</span> <span class="keyword">implements</span> <span class="title class_">Service</span> &#123;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Component(&quot;service2&quot;)</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Service2</span> <span class="keyword">implements</span> <span class="title class_">Service</span> &#123;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Component(&quot;service3&quot;)</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Service3</span> <span class="keyword">implements</span> <span class="title class_">Service</span> &#123;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>我们想依赖注入一个<code>Service</code>:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Autowired</span></span><br><span class="line"><span class="keyword">private</span> Service service;</span><br></pre></td></tr></table></figure>

<p>在这种情况下，<code>spring</code>是不知道具体使用哪一个<code>Service</code>的实现，有两种方法可以解决：</p>
<ol>
<li>在注入的时候加上<code>@Qualifier</code>注解指定<code>Bean</code>的名称</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Autowired</span></span><br><span class="line"><span class="meta">@Qualifier(&quot;service2&quot;)</span></span><br><span class="line"><span class="keyword">private</span> Service service;</span><br></pre></td></tr></table></figure>

<ol start="2">
<li>使用<code>@Primary</code>注解，加了<code>@Primary</code>注解的<code>Bean</code>比同类型的<code>Bean</code>在注入时优先级更高，因此注入时会优先选择添加了<code>@Primary</code>注解的<code>Bean</code></li>
</ol>
<p><code>@Primary</code>注解是在组件扫描的时候进行解析的，<code>spring</code>会将<code>@Primary</code>作为一个属性注入到<code>BeanDefinition</code>中，即当前<code>Bean</code>是否标记了<code>@Primary</code>注解，因此在<code>spring</code>不确定注入哪个<code>Bean</code>时会根据此标记进行筛选。</p>
<p>编写代码测试：</p>
<p>在<code>Service2</code>上添加<code>@Primary</code>注解：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Primary</span></span><br><span class="line"><span class="meta">@Component(&quot;service2&quot;)</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Service2</span> <span class="keyword">implements</span> <span class="title class_">Service</span> &#123;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>模拟<code>@Primary</code>注解的解析：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">testPrimary</span><span class="params">(DefaultListableBeanFactory beanFactory)</span> <span class="keyword">throws</span> NoSuchFieldException &#123;</span><br><span class="line">    <span class="type">DependencyDescriptor</span> <span class="variable">dd</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DependencyDescriptor</span>(Target.class.getDeclaredField(<span class="string">&quot;service&quot;</span>), <span class="literal">false</span>);</span><br><span class="line">    Class&lt;?&gt; type = dd.getDependencyType();</span><br><span class="line">    <span class="keyword">for</span> (String name : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, type)) &#123;</span><br><span class="line">        <span class="keyword">if</span> (beanFactory.getMergedBeanDefinition(name).isPrimary()) &#123;</span><br><span class="line">            System.out.println(name);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>编写<code>main()</code>调用：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> NoSuchFieldException &#123;</span><br><span class="line">    <span class="type">AnnotationConfigApplicationContext</span> <span class="variable">context</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AnnotationConfigApplicationContext</span>(A47_3.class);</span><br><span class="line">    <span class="type">DefaultListableBeanFactory</span> <span class="variable">beanFactory</span> <span class="operator">=</span> context.getDefaultListableBeanFactory();</span><br><span class="line">    testPrimary(beanFactory);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>查看输出：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">service2</span><br></pre></td></tr></table></figure>

<p>如果既没有使用<code>@Qualifier</code>注解也没有使用<code>@Primary</code>注解，还有最后一道防线，也就是根据属性的名称进行区分，<code>spring</code>将根据属性的名称进行匹配。</p>
<p>修改属性名称：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Autowired</span></span><br><span class="line"><span class="keyword">private</span> Service service3;</span><br></pre></td></tr></table></figure>

<p>模拟根据属性名称的解析：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">testDefault</span><span class="params">(DefaultListableBeanFactory beanFactory)</span> <span class="keyword">throws</span> NoSuchFieldException &#123;</span><br><span class="line">    <span class="type">DependencyDescriptor</span> <span class="variable">dd</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DependencyDescriptor</span>(Target.class.getDeclaredField(<span class="string">&quot;service3&quot;</span>), <span class="literal">false</span>);</span><br><span class="line">    Class&lt;?&gt; type = dd.getDependencyType();</span><br><span class="line">    <span class="keyword">for</span> (String name : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, type)) &#123;</span><br><span class="line">        <span class="keyword">if</span> (name.equals(dd.getDependencyName())) &#123;</span><br><span class="line">            System.out.println(name);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>编写<code>main()</code>调用：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> NoSuchFieldException &#123;</span><br><span class="line">    <span class="type">AnnotationConfigApplicationContext</span> <span class="variable">context</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AnnotationConfigApplicationContext</span>(A47_3.class);</span><br><span class="line">    <span class="type">DefaultListableBeanFactory</span> <span class="variable">beanFactory</span> <span class="operator">=</span> context.getDefaultListableBeanFactory();</span><br><span class="line">    testDefault(beanFactory);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>查看输出：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">service3</span><br></pre></td></tr></table></figure>

<p>以上三种方式的优先级如下：</p>
<ol>
<li>使用<code>@Qualifier</code>注解进行匹配</li>
<li>使用<code>@Primary</code>注解进行匹配</li>
<li>使用<code>Bean</code>的名称进行匹配</li>
</ol>
<h1 id="事件监听器"><a href="#事件监听器" class="headerlink" title="事件监听器"></a><strong>事件监听器</strong></h1><h2 id="实现ApplicationListener接口"><a href="#实现ApplicationListener接口" class="headerlink" title="实现ApplicationListener接口"></a>实现ApplicationListener接口</h2><p><code>spring</code>中事件机制，可以实现业务的解耦，这也是观察者模式的典型应用。</p>
<p>下面我们看一段代码：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">MyService</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Logger</span> <span class="variable">log</span> <span class="operator">=</span> LoggerFactory.getLogger(MyService.class);</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">doBusiness</span><span class="params">()</span> &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;主线业务&quot;</span>);</span><br><span class="line">        <span class="comment">// 主线业务完成后需要做一些支线业务</span></span><br><span class="line">        log.debug(<span class="string">&quot;发送短信&quot;</span>);</span><br><span class="line">        log.debug(<span class="string">&quot;发送邮件&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>以上代码有一个问题，就是主线业务与支线业务耦合，我们可以采用事件发布与监听的方式去解耦。</p>
<p>创建一个自定义事件，需要继承<code>ApplicationEvent</code>：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">MyEvent</span> <span class="keyword">extends</span> <span class="title class_">ApplicationEvent</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">MyEvent</span><span class="params">(Object source)</span> &#123;</span><br><span class="line">        <span class="built_in">super</span>(source);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在完成主线业务后发布一个事件：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">MyService</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Logger</span> <span class="variable">log</span> <span class="operator">=</span> LoggerFactory.getLogger(MyService.class);</span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> ApplicationEventPublisher publisher; </span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">doBusiness</span><span class="params">()</span> &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;主线业务&quot;</span>);</span><br><span class="line">        <span class="comment">// 发布事件</span></span><br><span class="line">        publisher.publishEvent(<span class="keyword">new</span> <span class="title class_">MyEvent</span>(<span class="string">&quot;MyService.doBusiness()&quot;</span>));</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>监听事件可以实现<code>ApplicationListener</code>接口，同时设置泛型只关注目标类型的事件：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">SmsApplicationListener</span> <span class="keyword">implements</span> <span class="title class_">ApplicationListener</span>&lt;MyEvent&gt; &#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Logger</span> <span class="variable">log</span> <span class="operator">=</span> LoggerFactory.getLogger(SmsApplicationListener.class);</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">onApplicationEvent</span><span class="params">(MyEvent event)</span> &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;发送短信&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">EmailApplicationListener</span> <span class="keyword">implements</span> <span class="title class_">ApplicationListener</span>&lt;MyEvent&gt; &#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Logger</span> <span class="variable">log</span> <span class="operator">=</span> LoggerFactory.getLogger(EmailApplicationListener.class);</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">onApplicationEvent</span><span class="params">(MyEvent event)</span> &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;发送邮件&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>创建<code>main()</code>方法测试：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">    <span class="type">AnnotationConfigApplicationContext</span> <span class="variable">context</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AnnotationConfigApplicationContext</span>(A48_1.class);</span><br><span class="line">    context.getBean(MyService.class).doBusiness();</span><br><span class="line">    context.close();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>查看输出：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">[DEBUG] 23:09:07.579 [main] com.itheima.a48.A48_1$MyService     - 主线业务 </span><br><span class="line">[DEBUG] 23:09:07.595 [main] c.i.a.A48_1$EmailApplicationListener - 发送邮件 </span><br><span class="line">[DEBUG] 23:09:07.595 [main] c.i.a.A48_1$SmsApplicationListener  - 发送短信 </span><br></pre></td></tr></table></figure>

<p>主线业务与支线业务已经解耦，如果不再需要发短信的功能，只需要取消事件监听即可，不需要修改主线业务的代码，这就是解耦的好处。</p>
<h2 id="使用-EventListener注解"><a href="#使用-EventListener注解" class="headerlink" title="使用@EventListener注解"></a>使用@EventListener注解</h2><p><code>spring</code>还支持通过<code>@EventListener</code>注解来监听事件，<code>@EventListener</code>注解标注的方法的参数类型就是监听的事件的类型，例如：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">SmsService</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Logger</span> <span class="variable">log</span> <span class="operator">=</span> LoggerFactory.getLogger(SmsService.class);</span><br><span class="line">    <span class="meta">@EventListener</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">listener</span><span class="params">(MyEvent myEvent)</span> &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;发送短信&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">EmailService</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Logger</span> <span class="variable">log</span> <span class="operator">=</span> LoggerFactory.getLogger(EmailService.class);</span><br><span class="line">    <span class="meta">@EventListener</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">listener</span><span class="params">(MyEvent myEvent)</span> &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;发送邮件&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>运行<code>main()</code>方法，查看输出：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">[DEBUG] 23:09:07.579 [main] com.itheima.a48.A48_1$MyService     - 主线业务 </span><br><span class="line">[DEBUG] 23:09:07.595 [main] c.i.a.A48_1$EmailApplicationListener - 发送邮件 </span><br><span class="line">[DEBUG] 23:09:07.595 [main] c.i.a.A48_1$SmsApplicationListener  - 发送短信 </span><br></pre></td></tr></table></figure>

<p>以上事件的发布与监听是同步的，由一个线程执行，我们可以将其优化异步，通过其他线程来执行支线业务。</p>
<p><code>ApplicationEventPublisher</code>底层是调用了<code>SimpleApplicationEventMulticaster</code>真正发事件，默认是单线程发送，我们可以设置用线程池来发送。</p>
<p>我们需要注入自己的<code>SimpleApplicationEventMulticaster</code>并设置线程池，注意<code>Bean</code>的名称必须为<code>applicationEventMulticaster</code>，这样才能覆盖原有实现：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">* 创建线程池</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="meta">@Bean</span></span><br><span class="line"><span class="keyword">public</span> ThreadPoolTaskExecutor <span class="title function_">executor</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="type">ThreadPoolTaskExecutor</span> <span class="variable">executor</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ThreadPoolTaskExecutor</span>();</span><br><span class="line">    executor.setCorePoolSize(<span class="number">3</span>);</span><br><span class="line">    executor.setMaxPoolSize(<span class="number">10</span>);</span><br><span class="line">    executor.setQueueCapacity(<span class="number">100</span>);</span><br><span class="line">    <span class="keyword">return</span> executor;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 注意名称必须为applicationEventMulticaster，这样才能覆盖原有实现</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> executor</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Bean</span></span><br><span class="line"><span class="keyword">public</span> SimpleApplicationEventMulticaster <span class="title function_">applicationEventMulticaster</span><span class="params">(ThreadPoolTaskExecutor executor)</span> &#123;</span><br><span class="line">    <span class="type">SimpleApplicationEventMulticaster</span> <span class="variable">multicaster</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">SimpleApplicationEventMulticaster</span>();</span><br><span class="line">    multicaster.setTaskExecutor(executor);</span><br><span class="line">    <span class="keyword">return</span> multicaster;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>运行<code>main()</code>方法，查看输出：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">[DEBUG] 23:20:33.307 [main] com.itheima.a48.A48_2$MyService     - 主线业务 </span><br><span class="line">[DEBUG] 23:20:33.316 [executor-2] com.itheima.a48.A48_2$SmsService    - 发送短信 </span><br><span class="line">[DEBUG] 23:20:33.317 [executor-1] com.itheima.a48.A48_2$EmailService  - 发送邮件 </span><br></pre></td></tr></table></figure>

<p>已经是使用线程池中的线程去执行支线业务。</p>
<h2 id="模拟事件监听原理"><a href="#模拟事件监听原理" class="headerlink" title="模拟事件监听原理"></a>模拟事件监听原理</h2><p>首先自定义一个<code>Listener</code>注解：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Retention(RetentionPolicy.RUNTIME)</span></span><br><span class="line"><span class="meta">@Target(ElementType.METHOD)</span></span><br><span class="line"><span class="meta">@interface</span> MyListener &#123;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>实现逻辑解析我们自定义的注解，主要步骤如下：</p>
<ol>
<li>获取容器中所有的<code>Bean</code></li>
<li>获取每个<code>Bean</code>中的所有方法</li>
<li>判断方法上是否有我们自定义的注解</li>
<li>从方法参数中获取需要监听的事件类型</li>
<li>实现<code>ApplicationListener</code>接口，重写<code>onApplicationEvent()</code>方法</li>
<li>在<code>onApplicationEvent()</code>方法中判断发生的事件是否为监听器监听的事件类型</li>
<li>最后将我们实现的<code>ApplicationListener</code>加入<code>AnnotationConfigApplicationContext</code>中的<code>ApplicationListener</code>中</li>
</ol>
<p>具体代码如下：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span> (String name : context.getBeanDefinitionNames()) &#123;</span><br><span class="line">    <span class="type">Object</span> <span class="variable">bean</span> <span class="operator">=</span> context.getBean(name);</span><br><span class="line">    <span class="keyword">for</span> (Method method : bean.getClass().getMethods()) &#123;</span><br><span class="line">        <span class="keyword">if</span> (method.isAnnotationPresent(MyListener.class)) &#123;</span><br><span class="line">            context.addApplicationListener((event) -&gt; &#123;</span><br><span class="line">                System.out.println(event);</span><br><span class="line">                Class&lt;?&gt; eventType = method.getParameterTypes()[<span class="number">0</span>];<span class="comment">// 监听器方法需要的事件类型</span></span><br><span class="line">                <span class="keyword">if</span> (eventType.isAssignableFrom(event.getClass())) &#123;</span><br><span class="line">                    <span class="keyword">try</span> &#123;</span><br><span class="line">                        method.invoke(bean, event);</span><br><span class="line">                    &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">                        e.printStackTrace();</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>我们可以在做一个优化，将以上逻辑写到一个后处理器中，我们可以实现<code>SmartInitializingSingleton</code>接口，这个接口会在所有单例对象初始化完毕之后调用。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Bean</span></span><br><span class="line"><span class="keyword">public</span> SmartInitializingSingleton <span class="title function_">smartInitializingSingleton</span><span class="params">(ConfigurableApplicationContext context)</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> () -&gt; &#123;</span><br><span class="line">        <span class="keyword">for</span> (String name : context.getBeanDefinitionNames()) &#123;</span><br><span class="line">            <span class="type">Object</span> <span class="variable">bean</span> <span class="operator">=</span> context.getBean(name);</span><br><span class="line">            <span class="keyword">for</span> (Method method : bean.getClass().getMethods()) &#123;</span><br><span class="line">                <span class="keyword">if</span> (method.isAnnotationPresent(MyListener.class)) &#123;</span><br><span class="line">                    context.addApplicationListener((event) -&gt; &#123;</span><br><span class="line">                        System.out.println(event);</span><br><span class="line">                        Class&lt;?&gt; eventType = method.getParameterTypes()[<span class="number">0</span>];<span class="comment">// 监听器方法需要的事件类型</span></span><br><span class="line">                        <span class="keyword">if</span> (eventType.isAssignableFrom(event.getClass())) &#123;</span><br><span class="line">                            <span class="keyword">try</span> &#123;</span><br><span class="line">                                method.invoke(bean, event);</span><br><span class="line">                            &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">                                e.printStackTrace();</span><br><span class="line">                            &#125;</span><br><span class="line">                        &#125;</span><br><span class="line">                    &#125;);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>运行<code>main()</code>方法，查看输出：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">org.springframework.context.event.ContextRefreshedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@3bd94634, started on Fri Apr 14 23:44:32 CST 2023]</span><br><span class="line">org.springframework.context.event.ContextRefreshedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@3bd94634, started on Fri Apr 14 23:44:32 CST 2023]</span><br><span class="line">[DEBUG] 23:44:33.068 [main] com.itheima.a48.A48_3$MyService     - 主线业务 </span><br><span class="line">com.itheima.a48.A48_3$MyEvent[source=MyService.doBusiness()]</span><br><span class="line">[DEBUG] 23:44:33.078 [main] com.itheima.a48.A48_3$EmailService  - 发送邮件 </span><br><span class="line">com.itheima.a48.A48_3$MyEvent[source=MyService.doBusiness()]</span><br><span class="line">[DEBUG] 23:44:33.078 [main] com.itheima.a48.A48_3$SmsService    - 发送短信 </span><br><span class="line">org.springframework.context.event.ContextClosedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@3bd94634, started on Fri Apr 14 23:44:32 CST 2023]</span><br><span class="line">org.springframework.context.event.ContextClosedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@3bd94634, started on Fri Apr 14 23:44:32 CST 2023]</span><br></pre></td></tr></table></figure>

<h1 id="事件发布器"><a href="#事件发布器" class="headerlink" title="事件发布器"></a><strong>事件发布器</strong></h1><p>事件发布器对应的接口为<code>ApplicationEventMulticaster</code>，<code>spring</code>提供了一个比较常用的实现<code>SimpleApplicationEventMulticaster</code>，我们也可以自定义实现。</p>
<p><code>ApplicationEventMulticaster</code>接口中有两个重要方法：</p>
<ol>
<li><code>addApplicationListenerBean()</code>：收集所有的监听器</li>
<li><code>multicastEvent()</code>：发布事件时会调用此方法</li>
</ol>
<p>我们主要实现以上两个方法，其他方法我们可以用抽象类给空实现：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">abstract</span> <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">AbstractApplicationEventMulticaster</span> <span class="keyword">implements</span> <span class="title class_">ApplicationEventMulticaster</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">addApplicationListener</span><span class="params">(ApplicationListener&lt;?&gt; listener)</span> &#123;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">addApplicationListenerBean</span><span class="params">(String listenerBeanName)</span> &#123;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">removeApplicationListener</span><span class="params">(ApplicationListener&lt;?&gt; listener)</span> &#123;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">removeApplicationListenerBean</span><span class="params">(String listenerBeanName)</span> &#123;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">removeApplicationListeners</span><span class="params">(Predicate&lt;ApplicationListener&lt;?&gt;&gt; predicate)</span> &#123;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">removeApplicationListenerBeans</span><span class="params">(Predicate&lt;String&gt; predicate)</span> &#123;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">removeAllListeners</span><span class="params">()</span> &#123;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">multicastEvent</span><span class="params">(ApplicationEvent event)</span> &#123;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">multicastEvent</span><span class="params">(ApplicationEvent event, ResolvableType eventType)</span> &#123;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>我们实现<code>AbstractApplicationEventMulticaster</code>抽象类：</p>
<ol>
<li>在<code>addApplicationListenerBean()</code>方法中，我们获取<code>listener</code>的实例加入到<code>listeners</code>集合中</li>
<li>在<code>multicastEvent()</code>方法中，我们调用监听器的<code>onApplicationEvent()</code>方法</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Bean</span> </span><br><span class="line"><span class="keyword">public</span> ApplicationEventMulticaster <span class="title function_">applicationEventMulticaster</span><span class="params">(ConfigurableApplicationContext context)</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">AbstractApplicationEventMulticaster</span>() &#123;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">private</span> List&lt;ApplicationListener&gt; listeners = <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;();</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 收集监听器</span></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">addApplicationListenerBean</span><span class="params">(String name)</span> &#123;</span><br><span class="line">            <span class="type">ApplicationListener</span> <span class="variable">listener</span> <span class="operator">=</span> context.getBean(name, ApplicationListener.class);</span><br><span class="line">            System.out.println(listener);</span><br><span class="line">            listeners.add(listener);</span><br><span class="line"></span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 发布事件</span></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">multicastEvent</span><span class="params">(ApplicationEvent event,ResolvableType eventType)</span> &#123;</span><br><span class="line">            <span class="keyword">for</span> (ApplicationListener listener : listeners) &#123;</span><br><span class="line">                listener.onApplicationEvent(event);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>使用自定义的监听器，查看输出：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">Exception in thread &quot;main&quot; java.lang.ClassCastException: class org.springframework.context.event.ContextRefreshedEvent cannot be cast to class com.itheima.a49.A49$MyEvent (org.springframework.context.event.ContextRefreshedEvent and com.itheima.a49.A49$MyEvent are in unnamed module of loader &#x27;app&#x27;)</span><br><span class="line">        at com.itheima.a49.A49$EmailApplicationListener.onApplicationEvent(A49.java:120)</span><br><span class="line">        at com.itheima.a49.A49$1.multicastEvent(A49.java:84)</span><br><span class="line">        at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:421)</span><br><span class="line">        at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:378)</span><br><span class="line">        at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:938)</span><br><span class="line">        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:586)</span><br><span class="line">        at org.springframework.context.annotation.AnnotationConfigApplicationContext.&lt;init&gt;(AnnotationConfigApplicationContext.java:93)</span><br><span class="line">        at com.itheima.a49.A49.main(A49.java:25)Exception in thread &quot;main&quot; java.lang.ClassCastException: class org.springframework.context.event.ContextRefreshedEvent cannot be cast to class com.itheima.a49.A49$MyEvent (org.springframework.context.event.ContextRefreshedEvent and com.itheima.a49.A49$MyEvent are in unnamed module of loader &#x27;app&#x27;)</span><br><span class="line">        at com.itheima.a49.A49$EmailApplicationListener.onApplicationEvent(A49.java:120)</span><br><span class="line">        at com.itheima.a49.A49$1.multicastEvent(A49.java:84)</span><br><span class="line">        at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:421)</span><br><span class="line">        at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:378)</span><br><span class="line">        at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:938)</span><br><span class="line">        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:586)</span><br><span class="line">        at org.springframework.context.annotation.AnnotationConfigApplicationContext.&lt;init&gt;(AnnotationConfigApplicationContext.java:93)</span><br><span class="line">        at com.itheima.a49.A49.main(A49.java:25)</span><br></pre></td></tr></table></figure>

<p>发现报了一个错误，这是因为容器中存在其它的事件类型，例如<code>ContextRefreshedEvent</code>，但是我们需要监听的事件为<code>MyEvent</code>类型，因此调用<code>onApplicationEvent()</code>方法时，<code>ContextRefreshedEvent</code>会强制转换为<code>MyEvent</code>会抛出异常。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">onApplicationEvent</span><span class="params">(MyEvent event)</span> &#123;</span><br><span class="line">    log.debug(<span class="string">&quot;发送短信&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>我们可以在调用时判断监听器监听的事件类型是否支持<code>multicastEvent()</code>方法传入的事件类型。</p>
<p>我们可以使用<code>ApplicationListener</code>的子接口<code>GenericApplicationListener</code>：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">GenericApplicationListener</span> <span class="keyword">extends</span> <span class="title class_">SmartApplicationListener</span> &#123;</span><br><span class="line">    <span class="keyword">default</span> <span class="type">boolean</span> <span class="title function_">supportsEventType</span><span class="params">(Class&lt;? extends ApplicationEvent&gt; eventType)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">this</span>.supportsEventType(ResolvableType.forClass(eventType));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="type">boolean</span> <span class="title function_">supportsEventType</span><span class="params">(ResolvableType eventType)</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><code>GenericApplicationListener</code>提供了一个<code>supportsEventType()</code>方法，返回一个<code>boolean</code>值，表示当前监听器是否支持传入的事件类型。</p>
<p>我们可以使用<code>GenericApplicationListener</code>对<code>ApplicationListener</code>做一个封装：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Bean</span></span><br><span class="line"><span class="keyword">public</span> ApplicationEventMulticaster <span class="title function_">applicationEventMulticaster</span><span class="params">(ConfigurableApplicationContext context, ThreadPoolTaskExecutor executor)</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">AbstractApplicationEventMulticaster</span>() &#123;</span><br><span class="line">        <span class="keyword">private</span> List&lt;GenericApplicationListener&gt; listeners = <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;();</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 收集监听器</span></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">addApplicationListenerBean</span><span class="params">(String name)</span> &#123;</span><br><span class="line">            <span class="type">ApplicationListener</span> <span class="variable">listener</span> <span class="operator">=</span> context.getBean(name, ApplicationListener.class);</span><br><span class="line">            System.out.println(listener);</span><br><span class="line">            <span class="comment">// 获取该监听器支持的事件类型</span></span><br><span class="line">            <span class="type">ResolvableType</span> <span class="variable">type</span> <span class="operator">=</span> ResolvableType.forClass(listener.getClass()).getInterfaces()[<span class="number">0</span>].getGeneric();</span><br><span class="line">            System.out.println(type);</span><br><span class="line"></span><br><span class="line">            <span class="comment">// 将原始的 listener 封装为支持事件类型检查的 listener</span></span><br><span class="line">            <span class="type">GenericApplicationListener</span> <span class="variable">genericApplicationListener</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">GenericApplicationListener</span>() &#123;</span><br><span class="line">                <span class="comment">// 是否支持某事件类型                真实的事件类型</span></span><br><span class="line">                <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">supportsEventType</span><span class="params">(ResolvableType eventType)</span> &#123;</span><br><span class="line">                    <span class="keyword">return</span> type.isAssignableFrom(eventType);</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">onApplicationEvent</span><span class="params">(ApplicationEvent event)</span> &#123;</span><br><span class="line">                    executor.submit(() -&gt; listener.onApplicationEvent(event));</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;;</span><br><span class="line"></span><br><span class="line">            listeners.add(genericApplicationListener);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 发布事件</span></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">multicastEvent</span><span class="params">(ApplicationEvent event, ResolvableType eventType)</span> &#123;</span><br><span class="line">            <span class="keyword">for</span> (GenericApplicationListener listener : listeners) &#123;</span><br><span class="line">                <span class="comment">// 监听器是否支持event事件类型</span></span><br><span class="line">                <span class="keyword">if</span> (listener.supportsEventType(ResolvableType.forClass(event.getClass()))) &#123;</span><br><span class="line">                    listener.onApplicationEvent(event);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>完整代码如下：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">A49</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="type">AnnotationConfigApplicationContext</span> <span class="variable">context</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AnnotationConfigApplicationContext</span>(A49.class);</span><br><span class="line">        context.getBean(MyService.class).doBusiness();</span><br><span class="line">        context.close();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="keyword">public</span> ThreadPoolTaskExecutor <span class="title function_">executor</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="type">ThreadPoolTaskExecutor</span> <span class="variable">executor</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ThreadPoolTaskExecutor</span>();</span><br><span class="line">        executor.setCorePoolSize(<span class="number">3</span>);</span><br><span class="line">        executor.setMaxPoolSize(<span class="number">10</span>);</span><br><span class="line">        executor.setQueueCapacity(<span class="number">100</span>);</span><br><span class="line">        <span class="keyword">return</span> executor;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">MyEvent</span> <span class="keyword">extends</span> <span class="title class_">ApplicationEvent</span> &#123;</span><br><span class="line">        <span class="keyword">public</span> <span class="title function_">MyEvent</span><span class="params">(Object source)</span> &#123;</span><br><span class="line">            <span class="built_in">super</span>(source);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Component</span></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">MyService</span> &#123;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Logger</span> <span class="variable">log</span> <span class="operator">=</span> LoggerFactory.getLogger(MyService.class);</span><br><span class="line">        <span class="meta">@Autowired</span></span><br><span class="line">        <span class="keyword">private</span> ApplicationEventPublisher publisher; <span class="comment">// applicationContext</span></span><br><span class="line"></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">doBusiness</span><span class="params">()</span> &#123;</span><br><span class="line">            log.debug(<span class="string">&quot;主线业务&quot;</span>);</span><br><span class="line">            <span class="comment">// 主线业务完成后需要做一些支线业务，下面是问题代码</span></span><br><span class="line">            publisher.publishEvent(<span class="keyword">new</span> <span class="title class_">MyEvent</span>(<span class="string">&quot;MyService.doBusiness()&quot;</span>));</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Component</span></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">SmsApplicationListener</span> <span class="keyword">implements</span> <span class="title class_">ApplicationListener</span>&lt;MyEvent&gt; &#123;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Logger</span> <span class="variable">log</span> <span class="operator">=</span> LoggerFactory.getLogger(SmsApplicationListener.class);</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">onApplicationEvent</span><span class="params">(MyEvent event)</span> &#123;</span><br><span class="line">            log.debug(<span class="string">&quot;发送短信&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Component</span></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">EmailApplicationListener</span> <span class="keyword">implements</span> <span class="title class_">ApplicationListener</span>&lt;MyEvent&gt; &#123;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Logger</span> <span class="variable">log</span> <span class="operator">=</span> LoggerFactory.getLogger(EmailApplicationListener.class);</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">onApplicationEvent</span><span class="params">(MyEvent event)</span> &#123;</span><br><span class="line">            log.debug(<span class="string">&quot;发送邮件&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="keyword">public</span> ApplicationEventMulticaster <span class="title function_">applicationEventMulticaster</span><span class="params">(ConfigurableApplicationContext context, ThreadPoolTaskExecutor executor)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">AbstractApplicationEventMulticaster</span>() &#123;</span><br><span class="line">            <span class="keyword">private</span> List&lt;GenericApplicationListener&gt; listeners = <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;();</span><br><span class="line"></span><br><span class="line">            <span class="comment">// 收集监听器</span></span><br><span class="line">            <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">addApplicationListenerBean</span><span class="params">(String name)</span> &#123;</span><br><span class="line">                <span class="type">ApplicationListener</span> <span class="variable">listener</span> <span class="operator">=</span> context.getBean(name, ApplicationListener.class);</span><br><span class="line">                System.out.println(listener);</span><br><span class="line">                <span class="comment">// 获取该监听器支持的事件类型</span></span><br><span class="line">                <span class="type">ResolvableType</span> <span class="variable">type</span> <span class="operator">=</span> ResolvableType.forClass(listener.getClass()).getInterfaces()[<span class="number">0</span>].getGeneric();</span><br><span class="line">                System.out.println(type);</span><br><span class="line"></span><br><span class="line">                <span class="comment">// 将原始的 listener 封装为支持事件类型检查的 listener</span></span><br><span class="line">                <span class="type">GenericApplicationListener</span> <span class="variable">genericApplicationListener</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">GenericApplicationListener</span>() &#123;</span><br><span class="line">                    <span class="comment">// 是否支持某事件类型                真实的事件类型</span></span><br><span class="line">                    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">supportsEventType</span><span class="params">(ResolvableType eventType)</span> &#123;</span><br><span class="line">                        <span class="keyword">return</span> type.isAssignableFrom(eventType);</span><br><span class="line">                    &#125;</span><br><span class="line"></span><br><span class="line">                    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">onApplicationEvent</span><span class="params">(ApplicationEvent event)</span> &#123;</span><br><span class="line">                        executor.submit(() -&gt; listener.onApplicationEvent(event));</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;;</span><br><span class="line"></span><br><span class="line">                listeners.add(genericApplicationListener);</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="comment">// 发布事件</span></span><br><span class="line">            <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">multicastEvent</span><span class="params">(ApplicationEvent event, ResolvableType eventType)</span> &#123;</span><br><span class="line">                <span class="keyword">for</span> (GenericApplicationListener listener : listeners) &#123;</span><br><span class="line">                    <span class="keyword">if</span> (listener.supportsEventType(ResolvableType.forClass(event.getClass()))) &#123;</span><br><span class="line">                        listener.onApplicationEvent(event);</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">abstract</span> <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">AbstractApplicationEventMulticaster</span> <span class="keyword">implements</span> <span class="title class_">ApplicationEventMulticaster</span> &#123;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">addApplicationListener</span><span class="params">(ApplicationListener&lt;?&gt; listener)</span> &#123;</span><br><span class="line"></span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">addApplicationListenerBean</span><span class="params">(String listenerBeanName)</span> &#123;</span><br><span class="line"></span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">removeApplicationListener</span><span class="params">(ApplicationListener&lt;?&gt; listener)</span> &#123;</span><br><span class="line"></span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">removeApplicationListenerBean</span><span class="params">(String listenerBeanName)</span> &#123;</span><br><span class="line"></span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">removeApplicationListeners</span><span class="params">(Predicate&lt;ApplicationListener&lt;?&gt;&gt; predicate)</span> &#123;</span><br><span class="line"></span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">removeApplicationListenerBeans</span><span class="params">(Predicate&lt;String&gt; predicate)</span> &#123;</span><br><span class="line"></span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">removeAllListeners</span><span class="params">()</span> &#123;</span><br><span class="line"></span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">multicastEvent</span><span class="params">(ApplicationEvent event)</span> &#123;</span><br><span class="line"></span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">multicastEvent</span><span class="params">(ApplicationEvent event, ResolvableType eventType)</span> &#123;</span><br><span class="line"></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>运行启动类，查看控制台：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">com.itheima.a49.A49$EmailApplicationListener@5c7933ad</span><br><span class="line">com.itheima.a49.A49$MyEvent</span><br><span class="line">com.itheima.a49.A49$SmsApplicationListener@69c81773</span><br><span class="line">com.itheima.a49.A49$MyEvent</span><br><span class="line">[DEBUG] 13:52:41.808 [main] com.itheima.a49.A49$MyService       - 主线业务 </span><br><span class="line">[DEBUG] 13:52:41.821 [executor-1] c.i.a.A49$EmailApplicationListener  - 发送邮件 </span><br><span class="line">[DEBUG] 13:52:41.821 [executor-2] c.i.a49.A49$SmsApplicationListener  - 发送短信 </span><br></pre></td></tr></table></figure>
</article><div class="post-copyright"><div class="post-copyright__author"><span class="post-copyright-meta">文章作者: </span><span class="post-copyright-info"><a href>狼族少年、血狼</a></span></div><div class="post-copyright__type"><span class="post-copyright-meta">文章链接: </span><span class="post-copyright-info"><a href="https://geekwolfman.github.io/2023/04/15/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E5%85%AD%E7%AB%A0%E3%80%91%EF%BC%9AOTHER.html">https://geekwolfman.github.io/2023/04/15/Spring高级45讲【第六章】：OTHER.html</a></span></div><div class="post-copyright__notice"><span class="post-copyright-meta">版权声明: </span><span class="post-copyright-info">本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank">CC BY-NC-SA 4.0</a> 许可协议。转载请注明来自 <a href="https://geekwolfman.github.io" target="_blank">狼族少年、血狼</a>！</span></div></div><div class="tag_share"><div class="post-meta__tag-list"><a class="post-meta__tags" href="/tags/spring/">spring</a></div><div class="post_share"><div class="social-share" data-image="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E5%85%AD%E7%AB%A0%E3%80%91%EF%BC%9AOTHER/00cover.jpg" data-sites="facebook,twitter,wechat,weibo,qq"></div><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/butterfly-extsrc/sharejs/dist/css/share.min.css" media="print" onload="this.media='all'"><script src="https://cdn.jsdelivr.net/npm/butterfly-extsrc/sharejs/dist/js/social-share.min.js" defer></script></div></div><nav class="pagination-post" id="pagination"><div class="prev-post pull-left"><a href="/2023/04/16/%E6%89%8B%E5%86%99LRU%E7%AE%97%E6%B3%95.html" title="手写LRU算法"><img class="cover" src="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/%E6%89%8B%E5%86%99LRU%E7%AE%97%E6%B3%95/00cover.jpg" onerror="onerror=null;src='/img/404.jpg'" alt="cover of previous post"><div class="pagination-info"><div class="label">上一篇</div><div class="prev_info">手写LRU算法</div></div></a></div><div class="next-post pull-right"><a href="/2023/04/15/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%BA%94%E7%AB%A0%E3%80%91%EF%BC%9ABOOT.html" title="Spring高级45讲【第五章】：BOOT"><img class="cover" src="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%BA%94%E7%AB%A0%E3%80%91%EF%BC%9ABOOT/01cover.jpg" onerror="onerror=null;src='/img/404.jpg'" alt="cover of next post"><div class="pagination-info"><div class="label">下一篇</div><div class="next_info">Spring高级45讲【第五章】：BOOT</div></div></a></div></nav><div class="relatedPosts"><div class="headline"><i class="fas fa-thumbs-up fa-fw"></i><span>相关推荐</span></div><div class="relatedPosts-list"><div><a href="/2023/04/15/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%BA%94%E7%AB%A0%E3%80%91%EF%BC%9ABOOT.html" title="Spring高级45讲【第五章】：BOOT"><img class="cover" src="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%BA%94%E7%AB%A0%E3%80%91%EF%BC%9ABOOT/01cover.jpg" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2023-04-15</div><div class="title">Spring高级45讲【第五章】：BOOT</div></div></a></div><div><a href="/2023/04/15/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E5%9B%9B%E7%AB%A0%E3%80%91%EF%BC%9AWEB.html" title="Spring高级45讲【第四章】：WEB"><img class="cover" src="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E5%9B%9B%E7%AB%A0%E3%80%91%EF%BC%9AWEB/01cover.jpg" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2023-04-15</div><div class="title">Spring高级45讲【第四章】：WEB</div></div></a></div><div><a href="/2023/04/15/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%B8%89%E7%AB%A0%E3%80%91%EF%BC%9AAOP.html" title="Spring高级45讲【第三章】：AOP"><img class="cover" src="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%B8%89%E7%AB%A0%E3%80%91%EF%BC%9AAOP/01cover.jpg" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2023-04-15</div><div class="title">Spring高级45讲【第三章】：AOP</div></div></a></div><div><a href="/2023/04/15/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%BA%8C%E7%AB%A0%E3%80%91%EF%BC%9AIOC.html" title="Spring高级45讲【第二章】：IOC"><img class="cover" src="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%BA%8C%E7%AB%A0%E3%80%91%EF%BC%9AIOC/01cover.jpg" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2023-04-15</div><div class="title">Spring高级45讲【第二章】：IOC</div></div></a></div><div><a href="/2023/04/15/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%B8%80%E7%AB%A0%E3%80%91%EF%BC%9A%E5%AF%BC%E5%AD%A6.html" title="Spring高级45讲【第一章】：导学"><img class="cover" src="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%B8%80%E7%AB%A0%E3%80%91%EF%BC%9A%E5%AF%BC%E5%AD%A6/01cover.jpg" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2023-04-15</div><div class="title">Spring高级45讲【第一章】：导学</div></div></a></div><div><a href="/2023/03/23/%E6%89%8B%E5%86%99%E7%AE%80%E6%98%93%E7%89%88spring-web%E6%A1%86%E6%9E%B6.html" title="手写简易版spring web框架"><img class="cover" src="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/%E6%89%8B%E5%86%99%E7%AE%80%E6%98%93%E7%89%88spring-web%E6%A1%86%E6%9E%B6/01cover.jpg" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2023-03-23</div><div class="title">手写简易版spring web框架</div></div></a></div></div></div></div><div class="aside-content" id="aside-content"><div class="card-widget card-info"><div class="is-center"><div class="avatar-img"><img src="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/config/avatar/avatar.png" onerror="this.onerror=null;this.src='/img/friend_404.gif'" alt="avatar"/></div><div class="author-info__name">狼族少年、血狼</div><div class="author-info__description"></div></div><div class="card-info-data site-data is-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">57</div></a><a href="/tags/"><div class="headline">标签</div><div class="length-num">14</div></a><a href="/categories/"><div class="headline">分类</div><div class="length-num">9</div></a></div><a id="card-info-btn" target="_blank" rel="noopener" href="https://wpa.qq.com/msgrd?v=3&amp;uin=2370032534&amp;site=qq&amp;menu=yes&amp;jumpflag=1"><i class="fa-brands fa-qq"></i><span>添加博主QQ</span></a></div><div class="card-widget card-announcement"><div class="item-headline"><i class="fas fa-bullhorn fa-shake"></i><span>公告</span></div><div class="announcement_content">本站所有博文均是博主的学习笔记与个人理解，来源于网络，如有<span style="color:red;font-weight:bold;">侵权</span>请<a target="_blank" rel="noopener" href="https://wpa.qq.com/msgrd?v=3&uin=2370032534&site=qq&menu=yes&jumpflag=1" style="color:#49B1F5;font-weight:bold">联系我</a>进行删除🥰。</div></div><div class="sticky_layout"><div class="card-widget" id="card-toc"><div class="item-headline"><i class="fas fa-stream"></i><span>目录</span><span class="toc-percentage"></span></div><div class="toc-content"><ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#FactoryBean"><span class="toc-number">1.</span> <span class="toc-text">FactoryBean</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#Indexed%E5%8E%9F%E7%90%86"><span class="toc-number">2.</span> <span class="toc-text">@Indexed原理</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E4%BB%A3%E7%90%86%E8%BF%9B%E4%B8%80%E6%AD%A5%E7%90%86%E8%A7%A3"><span class="toc-number">3.</span> <span class="toc-text">代理进一步理解</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#Value%E8%A3%85%E9%85%8D%E5%BA%95%E5%B1%82"><span class="toc-number">4.</span> <span class="toc-text">@Value装配底层</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#Autowired%E8%A3%85%E9%85%8D%E5%BA%95%E5%B1%82"><span class="toc-number">5.</span> <span class="toc-text">@Autowired装配底层</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E4%BA%8B%E4%BB%B6%E7%9B%91%E5%90%AC%E5%99%A8"><span class="toc-number">6.</span> <span class="toc-text">事件监听器</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%AE%9E%E7%8E%B0ApplicationListener%E6%8E%A5%E5%8F%A3"><span class="toc-number">6.1.</span> <span class="toc-text">实现ApplicationListener接口</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%BD%BF%E7%94%A8-EventListener%E6%B3%A8%E8%A7%A3"><span class="toc-number">6.2.</span> <span class="toc-text">使用@EventListener注解</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%A8%A1%E6%8B%9F%E4%BA%8B%E4%BB%B6%E7%9B%91%E5%90%AC%E5%8E%9F%E7%90%86"><span class="toc-number">6.3.</span> <span class="toc-text">模拟事件监听原理</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E4%BA%8B%E4%BB%B6%E5%8F%91%E5%B8%83%E5%99%A8"><span class="toc-number">7.</span> <span class="toc-text">事件发布器</span></a></li></ol></div></div></div></div></main><footer id="footer"><div id="footer-wrap"><div class="copyright">&copy;2020 - 2023 By 狼族少年、血狼</div><div class="framework-info"><span>框架 </span><a target="_blank" rel="noopener" href="https://hexo.io">Hexo</a><span class="footer-separator">|</span><span>主题 </span><a target="_blank" rel="noopener" href="https://github.com/jerryc127/hexo-theme-butterfly">Butterfly</a></div></div></footer></div><div id="rightside"><div id="rightside-config-hide"><button id="readmode" type="button" title="阅读模式"><i class="fas fa-book-open"></i></button><button id="darkmode" type="button" title="浅色和深色模式转换"><i class="fas fa-adjust"></i></button><button id="hide-aside-btn" type="button" title="单栏和双栏切换"><i class="fas fa-arrows-alt-h"></i></button></div><div id="rightside-config-show"><button id="rightside_config" type="button" title="设置"><i class="fas fa-cog fa-spin"></i></button><button class="close" id="mobile-toc-button" type="button" title="目录"><i class="fas fa-list-ul"></i></button><button id="go-up" type="button" title="回到顶部"><span class="scroll-percent"></span><i class="fas fa-arrow-up"></i></button></div></div><div><script src="/js/utils.js"></script><script src="/js/main.js"></script><script src="https://cdn.jsdelivr.net/npm/@fancyapps/ui/dist/fancybox.umd.min.js"></script><div class="js-pjax"></div><script defer="defer" id="ribbon" src="https://cdn.jsdelivr.net/npm/butterfly-extsrc/dist/canvas-ribbon.min.js" size="150" alpha="0.6" zIndex="-1" mobile="false" data-click="false"></script><script async data-pjax src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script></div><div id="local-search"><div class="search-dialog"><nav class="search-nav"><span class="search-dialog-title">搜索</span><span id="loading-status"></span><button class="search-close-button"><i class="fas fa-times"></i></button></nav><div class="is-center" id="loading-database"><i class="fas fa-spinner fa-pulse"></i><span>  数据库加载中</span></div><div class="search-wrap"><div id="local-search-input"><div class="local-search-box"><input class="local-search-box--input" placeholder="搜索文章" type="text"/></div></div><hr/><div id="local-search-results"></div></div></div><div id="search-mask"></div><script src="/js/search/local-search.js"></script></div></body></html>